Projet collectif de fin de semestre pour le cours d’Aurélien Berra, “Humanités numériques 3”, à l’Université Paris Nanterre, décembre 2020 – Publication en ligne.

Si Aurélien Berra ne fait pas formellement partie de la liste des auteurs du présent document, ce travail n’aurait pas été possible sans lui : nous souhaitons lui adresser tous nos remerciements, non seulement pour ses cours qui nous ont initiés aux outils ici manipulés, pour son énoncé stimulant posant le problème auquel nous nous confrontons ici, mais encore pour sa disponibilité ainsi que ses nombreuses remarques, ressources et indications, prodiguées au cours de notre travail et suite à ses relectures très attentives. Nous avons tenté d’en tenir compte et d’intégrer ses apports autant que possible, si bien que ce travail est aussi un peu le sien.

Analyse de nomenclatures des corpus de littérature antique (TLG et PHI)

Présentation

Le développement des humanités numériques s’est accompagné de l’émergence de plusieurs innovations renouvelant les pratiques des chercheurs en humanités classiques. La création de bibliothèques interactives en fait partie, à l’instar du Thesaurus Linguae Graecae (TLG) et de la Bibliothèque Numérique Perseus. Les sites offrant l’accès à ces deux bibliothèques disposent d’un grand nombre de fonctionnalités, mobilisables sur un canon très large d’auteurs et d’œuvres – accessibles gratuitement pour Perseus, et sur abonnement pour le TLG. L’étude d’œuvres y est ainsi grandement facilité par la mise à disposition de plusieurs dictionnaires, de propositions d’analyse grammaticale, de mises en parallèle entre les œuvres sélectionnées, et même d’analyses statistiques.

Celui qui a déjà parcouru les rayons virtuels de ces bibliothèques – et plus encore celui qui aura tenté d’exploiter informatiquement ces données – aura peut-être relevé que chaque auteur, et chaque œuvre, y possède un identifiant unique. Toute base de données informatique appelle effectivement à doter chaque élément qui la composent d’un identifiant pour en permettre une manipulation aisée – l’identifiant, généralement suite de nombres, confère en effet à l’élément qu’il désigne une stabilité qui en facilite l’accès : quand bien même le contenu ou le titre de cet élément changerait, l’identifiant, lui, demeure.

Deux classifications servent de référence fréquente pour désigner les œuvres classiques et leurs auteurs : il s’agit des identifiants attribués par le TLG, pour les textes grecs, et par le Packard Humanities Institute (PHI) pour les textes latins. Dans les deux cas, l’identifiant est numérique et est composé de quatre chiffres : Homère, par exemple, est assigné à l’identifiant 0012 dans le TLG. L’identifiant d’une œuvre est alors composé de l’identifiant de son auteur suivi d’un point puis de plusieurs autres chiffres pour caractériser l’œuvre en question.

Pour autant, la documentation portant sur la constitution de ces identifiants est lacunaire, et un rapide coup d’œil aux identifiants du TLG ne permet pas d’en discerner la logique d’attribution : la numérotation ne à première vue être ni alphabétique, ni chrnologique, ou en tout cas pas de manière univoque, et on remarque que les identifiants sont discontinus, certains manquants entre deux valeurs : on a bien Hésiode correspondant au 0020 et Nicandre au 0022, mais en revanche aucun auteur au numéro 21. On s’interroge alors sur la logique interne de ces identifiants – à moins qu’ils ne soient qu’arbitraires…

Nous nous proposons donc de mener l’enquête. Au départ informatique, cette enquête est aussi historique : élucider la ou les logiques auxquelles ces identifiants pourraient obéir, c’est aussi informer les choix qui ont été faits lors de la constitution de ces bases de données. Une analyse informatisée, paraît particulièrement indiquée pour tenter de résoudre l’énigme qui se présente à nous, les identifiants en question étant numériques et se comptant par centaines pour la codification du PHI, par milliers pour celle du TLG. Les données à étudier présentent l’avantage d’être aisément accessibles – davantage que des matériaux d’archives ou le recueil de témoignages – et nous tenterons de croiser les identifiants non seulement avec les noms des auteurs concernés, mais aussi avec leurs dates, le ou les genres littéraires auxquels ils se rattachent, ainsi que leur lieu d’exercice.

Ainsi cette étude, que nous conduisons avec le langage R, langage libre d’analyse de données, apporte au praticien des humanités numériques à l’esprit curieux, et à la connaissance historique, un éclairage utile et une méthode originale. Nous procéderons tout d’abord à une mise en forme systématique des données que nous sommes parvenus à récupérer, pour pouvoir dans une seconde partie les soumettre à analyses graphiques, d’où nous tirerons plusieurs résultats synthétisés en conclusion.

Notez au passage que notre étude se concentre sur les identifiants des auteurs, laissant de côté la logique de numérotation des œuvres : à première vue, chaque auteur a une numérotation propre à ses œuvres (001, 002…), bien que celle-ci pourrait suivre des logiques transversales, par exemple une classification chronologique par date d’écriture. C’est tout ce que nous en dirons, car il nous paraît prioritaire dans cette investigation de commencer par nous focaliser sur les auteurs ; après tout, c’est leur identifiant est le premier apparaissant sur une œuvre (0012.001, 0012.002…). Analyser plus finement la logique de numérotation des œuvres appellerait à une étude spécifique qui demanderait de formater différemment les données à notre disposition : ceci pourrait faire l’objet d’un travail ultérieur.

Démarche adoptée

Avant de nous atteler aux formatages et à l’exploration proprement dits, revenons un instant sur quelques grands principes méthodologiques qui guident notre investigation. Nous cherchons ici à expliquer une variable, à savoir un identifiant, par d’autres variables potentielles, comme le nom, la date, le lieu ou le genre littéraire.

Rappelons, pour clarifier les fondements de la terminologie que nous employons, qu’une “variable” est une caractéristique d’un élément considéré. Dans un tableau, les “variables” correspondent généralement aux colonnes, et les éléments considérés aux lignes. On peut aussi parler, pour les lignes, d’“observations”, d’“entrées” ou d’“individus”. Pour chaque individu, chaque variable prend une valeur ou une modalité particulière, c’est le “contenu” de la variable. Les modalités sont ainsi l’ensemble des valeurs que peuvent prendre une variable – plus précisément, on parle de “modalité” lorsque le nombre de valeurs possibles est fini. Par exemple, l’identifiant est une variable qui a une forme particulière, à savoir un numéro de 1 à 4 chiffres, et pour l’individu dénommé “Platon”, la variable “identifiant” prend la valeur “0059” – la variable “genre littéraire” quant à elle, dont la liste des modalités est définie à l’avance, prend pour “Platon” la modalité “philosophie”.

Schématiquement, tout ceci se présente sous cette forme :

. Variable 1 Variable 2
Individu 1 Valeur 1 Modalité A
Individu 2 Valeur 2 Modalité A
Individu 3 Valeur 3 Modalité B

Pour observer ce que nous obtenons dans notre cas, le lecteur peut se référer à la section “Données finales”.

Considérons un instant les types des variables qui sont en jeu, avant de présenter les étapes qui vont nous être nécessaires dans notre étude.

Types de variables

Pour y voir plus clair, distinguons la “nature” des variables qui sont en jeu. On peut différencier :

  • Les variables “continues” : il s’agit de variables numériques, sur lesquelles on peut effectuer des opérations mathématiques (calcul de moyenne, minimum, maximum…). Il s’agit par exemple des identifiants sous la forme de numéros ou de dates. (Notons au passage que les catégories que nous proposons ne correspondent pas scrupuleusement à des catégories statistiques consacrées : des puristes pourraient ici arguer notamment que lorsqu’il s’agit de nombres entiers, comme les identifiants ou les dates sous la forme d’années, on est en terminologie mathématique face à des variables qu’il faudrait dire discrètes plutôt que continues. Qu’importe, cela paraît de peu d’importance pour ce qui nous préoccupe ici.)

  • Les variables “catégorielles” : il s’agit de “catégories” dans lesquelles on range les individus, des sortes d’étiquettes, en nombre limité, qu’on applique chacune à plusieurs individus. Dans notre cas, elles seront sous la forme de chaînes de caractères. Il s’agit par exemple des genres littéraires ou des lieux. Les initiales des noms peuvent également en relever.

  • Les variables “singulières” : il s’agit de variables dont le contenu est singulier, et généralement unique, à chaque individu considéré. Typiquement, c’est le cas des noms des auteurs. La distinction avec les variables continues repose sur le fait qu’il s’agit de chaînes de caractères qu’il est plus difficile de transcrire en chiffres, et donc dont la manipulation peut différer.

Les variables continues présentent l’avantage de correspondre à une échelle déterminée : on peut facilement dire que 3 est supérieur à 1, ou que -500 est antérieur à -400. Néanmoins, les variables que nous avons appelées catégorielles ou singulières, peuvent également être “ordonnées”, selon un critère déterminé : pour les noms en particulier, l’ordre alphabétique paraît être un mode d’arrangement qui fait sens. Pour les lieux, on pourrait les ranger par catégorie emboîtée (ville, région, pays), ou encore selon un ordre particulier (par exemple, d’ouest en est). Ces variables “ordonnées” se rapprochent alors un peu des variables continues, car, comme ces dernières, on peut désormais dire si telle modalité vient après ou avant telle autre modalité dans l’ordre qu’on a choisi : “Aristote” vient avant “Platon” pour la variable “nom” ordonnée par ordre alphabétique.

Notons que nous avons cité ici les variables les plus évidentes – et les plus accessibles – qui semblent à première vue porter le plus de sens pour la question qui nous préoccupe. Néanmoins, il se pourrait que nous laissions alors de côté d’autres considérations, comme par exemple des dates particulières, de découverte des manuscrits par exemple ; ou encore, nous pourrions être trop peu précis en ce qui concerne le nom des auteurs : peut-être ceux-ci ont-il évolué dans le temps et dans l’espace, selon les langues et les appellations, ou bien peut-être faudrait-il établir des distinctions selon ce qui pourrait correspondre à des éléments comme le nom et le prénom, en constituant alors des sous-variables plus précises.

Saisir les corrélations

Pour comprendre les relations entre ces variables, notamment pour déterminer si elles sont corrélées ou non, et si oui, de quelle manière, nous allons mobiliser des analyses graphiques : plutôt que des analyses mathématiques à l’aveuglette, les graphiques paraissent offrir l’approche la plus flexible et compréhensive. Nous pourrons alors projeter les variables sur les axes, d’un plan habituel en deux dimensions, et éventuellement user de couleurs pour faire apparaître à travers elles une troisième dimension.

Il faut noter que nous devrons a priori toujours projeter la variable à expliquer, c’est-à-dire celle des identifiants (à moins que nous ne cherchions à distinguer des corrélations intermédiaires qui sont la cause première des relations observées – par exemple si le lieu est corrélé avec la date, on pourrait, en ne regardant que les identifiants et les lieux, penser qu’il y a corrélation, quand la véritable corrélation serait en réalité entre les identifiants et les dates).

A priori, les variables continues se prêtent bien à la projection sur un axe orienté, car elles correspondent à une échelle. Cela est vrai aussi, quoique dans une moindre mesure, pour les variables ordonnées, dont l’ordre peut apparaître au fil de l’axe. Les variables catégorielles (ordonnées ou non) quant à elles se prêtent bien à l’utilisation de couleurs, du fait qu’elles devraient être relativement peu nombreuses, et donc distinguables grâce à des couleurs différentes. Lorsqu’elles sont ordonnées (voire, dans un autre style, quand on a à faire à des variables continues), on pourrait de plus faire appel à un dégradé – par exemple, en attribuant des couleurs plus claires aux valeurs “inférieures”, et des couleurs plus sombres aux valeurs “supérieures”.

L’ajout d’une troisième dimension par la couleur pourra nous aider à distinguer une évolution dans le cas où la classification changerait de logique en cours de route, ou obéirait en fait à plusieurs logiques : par exemple, si les auteurs étaient regroupés par lieu, puis, au sein de chaque groupe constitué pour un lieu donné, qu’ils étaient classés par ordre alphabétique. On verrait ainsi, sur nos graphiques, soit des séquences d’éléments qui se suivent dans l’ordre alphabétique, chacune d’une couleur particulière (si on projette le nom sur un axe, et qu’on colore les lieux), soit des points regroupés ensemble par lieu, avec sur chacun un dégradé de couleurs correspondant à l’ordre alphabétique (si on projette les lieux sur un axe, et qu’on colore les initiales).

Étapes nécessaires

Nous devrons constituer nos données, en récupérant les informations appropriées (correspondance entre identifiants et noms des auteurs, dates des auteurs, genre littéraire…), puis faire en sorte de les traiter. Successivement, nous devrons :

  1. Récupérer des données (voir Chargement des données), depuis internet notamment, à partir de bases de données déjà constituées ;

  2. Formater ces données pour les rendre exploitables (voir 1. Formatage des données), notamment en s’assurant de l’homogénéité des catégories et en transformant certaines variables textuelles en variables numériques ;

  3. Réaliser des analyses à partir des données formatées (voir 2. Analyses graphiques), c’est-à-dire, ici, essentiellement des graphiques.

Préparatifs

Configuration générale

Chargement des bibliothèques externes.

pacman::p_load(
  here, jsonlite, knitr, skimr, tidyverse
)

Configuration du rendu.

# Disable globally some messages in the final rendering,
# such as minor warnings from external functions.
opts_chunk$set(
  message = FALSE,
  warning = FALSE
)

default_cols_nb <- 12
#' Print a vector as a kable.
#' Allows to fix auto-wrapped printed vector.
#' @param data Vector of data to print.
#' @param cols_nb Integer. Desired number of columns.
#' @return NULL Prints the table as a knitr::kable.
print_vector <- function(data, cols_nb = default_cols_nb) {
  tibble(val = data) %>%
    rowid_to_column() %>%
    mutate(
      group = rowid %% cols_nb,
      new_rowid = ceiling(rowid / cols_nb)
    ) %>%
    select(-rowid) %>%
    pivot_wider(names_from = group, values_from = val) %>%
    select(-new_rowid) %>%
    mutate_all(
      ~ replace_na(., "")
    ) %>% 
    knitr::kable(
      col.names = c()
    )
}

Déclaration de variables globales (qu’on pourrait aussi appeler des constantes).

# Input directory.
input_dir <- here("projet_final/data/")
# On Windows, the 'here' package deletes the final "/" although we need it, therefore we must add it again.
if (.Platform$OS.type == "windows") input_dir <- paste0(input_dir, "/")

# Variants for NA in the retrieved data.
na_variants <- c(
  "", "?", "\n", "...",
  "NA", "n.a.", "n",
  "none", "None", "one",
  "unknown", "Unknown",
  "Various", "Varia",
  "Uncertain"
)

# Note that we will declare colors in relevant section to present them,
# which is in the middle of the second section.

Nous déclarons ci-dessus une fois pour toutes les différentes chaînes de caractères pouvant être utilisées pour indiquer des données manquantes, dans les différentes variables des données originales, repérées au fil de nos explorations. Elles seront remplacées en une fois au début du formatage des données.

Chargement des données

La plupart des données que nous mobilisons sont récupérées depuis un tableur en ligne du Projet Perseus. Le tableur contient des entrées d’œuvres antiques, ainsi que des informations sur leurs auteurs qui pourraient nous être utiles, en particulier : nom, lieu, dates d’activité, de “début” et de “fin”. Il contient également les identifiants qu’on cherche à expliquer, à savoir les identifiants TLG et PHI.

phi_works_raw_df <- read_csv(paste0(input_dir, "latin_authors_by-perseus.csv"))
tlg_works_raw_df <- read_csv(paste0(input_dir, "greek_authors_by-perseus.csv"))

En complément, nous utiliserons la liste des genres récupérée depuis les fichiers du CLTK (Classical Language ToolKit, la boîte à outils des langues classiques). Il ne s’agit ici que des auteurs grecs – il aurait été possible de récupérer l’épithète de genre sur les noms des auteurs TLG tels qu’ils sont formatés dans la liste du Projet Perseus, mais autant profiter de ce formatage déjà établi.

tlg_epithets_raw_df <-
  read_json(paste0(input_dir, "greek_authors-epithets_by-cltk.json")) %>%
  enframe("genre", "code")

Notons que nous conserverons, dans l’environnement de développement, les tableaux avec les données d’origine chargés ici : cela nous permettra en effet, au cours du développement de nos analyses, d’éventuellement aller vérifier quelles étaient les données de base correspondantes.

1. Formatage des données

Variables recherchées

Pour consulter les données finales obtenues, rendez-vous à la fin de la section !

Pour rendre les données récupérées exploitables, nous devons en formaliser la structure en les “encodant” de sorte qu’elles correspondent aux analyses que nous souhaitons mener.

En fin de compte, les variables que nous obtiendrons seront les suivantes :

Nom Description Exemple Nature Type Source d’origine
code identifiant 0059 nombre continue Perseus
init initiale* P caractère catégorielle
ordonnée
Première lettre
de “nom”
name nom* Plato Phil. caractères singulière
ordonnée
Perseus
genre genre littéraire
(TLG uniquement)
Philosophici/-ae caractères catégorielle CLTK
place lieu Greece caractères catégorielle Perseus
date date -500 nombre continue** Copie de
“date d’activité”
date_active date d’activité,
ou siècle
-500 nombre continue** Perseus
date_begin date “de départ”,
ou de naissance
-427 nombre continue Perseus
date_end date “de fin”,
ou de mort
-348 nombre continue Perseus
Tableau des variables utilisées
(*) Nous serons par la suite amenés, au cours de nos analyses, à modifier les noms, et par conséquent les initiales, qui nous servent de référence. Nous travaillerons alors sur une copie du tableau d’origine.
(**) Le caractère continu de la “date d’activité” est ambigu : il s’agit en effet le plus souvent de siècles, si bien qu’on pourrait considérer qu’il s’agit d’une variable catégorielle ordonnée. Néanmoins, par commodité, nous la traiterons comme une variable proprement numérique, c’est-à-dire continue.

Pour obtenir ces données finales, exploitables statistiquement, nous avons dû faire plusieurs choix.

  • Pour les dates, nous conservons, pour chacune sus-mentionnée, une variable équivalente sous la forme de chaîne de caractères, plus détaillée et plus fidèle aux données de départ, mais plus difficilement exploitable statistiquement par des graphiques.

    Ces équivalents-caractères ressemblent à ceci :

    • 200bce?” correspond, avec une incertitude (?) à 200 avant notre ère (bce pour Before Common Era), et est traduit sous forme numérique en -200 ;

    • 100ce-200ce” désigne un intervalle compris entre 100 et 200 de notre ère (ce pour Common Era). Nous prenons alors la moyenne des deux extrémités, ce que nous donne 150.

  • En ce qui concerne le “siècle”, le fait de prendre la moyenne lorsqu’on est face à un intervalle brise l’homogénéité de la mesure. “100ce-200ce” correspond à “entre le premier et le second siècle”, néanmoins “150” ne correspond plus à un siècle, mais plutôt à un demi-siècle. De plus, nous avons un problème au tournant de l’ère : “100bce” correspond au premier siècle avant (années -100 à -1) et “100ce” au premier siècle après (années 1 à 100) : l’échelle des siècles passe directement du -1 au 1, sans 0 intermédiaire, alors que la considérer comme un nombre “normal” la fait passer par un 0.

    Ce dernier souci étant de peu d’importance et non évident à corriger, nous signalons simplement que les dates entre -100 et 100, quand nous prendrons les siècles (date_active ou date), seront étalées deux fois plus que relativement à des données correctement homogènes.

  • Pour les lieux, nous n’avons conservé que le pays, pour gagner en généralité et avoir des catégories plus amples – les données de départ comportaient également parfois la région et/ou la ville.

    Lorsque plusieurs lieux étaient indiqués, nous n’avons arbitrairement conservé que le dernier de la liste. Il aurait été possible, mais alors plus fastidieux, de récupérer ces lieux multiples pour les formater convenablement, en les attribuant à chaque auteur sous la forme d’un objet “liste”, pour ensuite dupliquer chaque ligne contenant plusieurs lieux. Cela nous aurait permis de faire une analyse plus complète des lieux ; un même auteur avec un seul identifiant aurait alors pu être représenté par plusieurs points, de sorte qu’il aurait été possible de repérer, sur les nuages de points, le lieu “aberrant” et le lieu “correct” vis-à-vis de la logique dominante qui se serait dégagée.

    Nous avons également relevé, mais sans y appliquer un traitement particulier, qu’il pouvait exister diverses appellations pour un espace géographique identique, en totalité ou en partie. Par exemple, nous observons les modalités “Ionia”, “Turkey”, “Anatolia” ou encore “Tunisia”, “North Africa”, “Africa”. Ces désignations sont probablement liées en partie à l’époque à laquelle appartient l’auteur : par exemple, “Ionia” serait plutôt l’appellation employée pour les poètes archaïques et les philosophes présocratiques, alors que “Turkey” correspondrait aux auteurs chrétiens. Cependant, cette explication ne semble pas s’appliquer à tous les lieux et à tous les auteurs puisque, comme nous pourrons l’observer dans les graphiques des paragraphes consacrés aux identifiants et lieux, le lieu “Turkey” concerne des auteurs dès le quatrième siècle avant notre ère. Comprendre la logique qui a conduit à désigner ces territoires en fonction des dates, et peut-être des genres, pourrait faire l’objet d’une étude à part entière. Nous avons cependant gardé les désignations de lieux telles que nous les avons récupérées dans nos données.

  • Pour les genres, lorsqu’un auteur appartenait à plusieurs genres, nous n’avons conservé que le premier genre qui apparaissait par ordre alphabétique – de même que nous venons de l’expliciter quant aux lieux multiples, il aurait alternativement été possible d’user d’objets “liste”.

  • On remarquera dans le tableau d’auteurs grecs au chapitre “Données finales obtenues” que certains genres littéraires figurent dans la colonne des noms d’auteurs (issue de Perseus) alors qu’elles sont manquantes dans celle des genres (dans le tableau importé CLTK). Une observation plus attentive permet cependant de remarquer que ces “genres” qui apparaissent dans la colonne (par exemple epistulae) font partie intégrante de la variable name ; ils ne sont pas qualifiants d’un auteur, mais désignent un corpus qualifié par le nom d’un auteur - réel, inconnu ou réinventé - désigné par la tradition. Par exemple, Alexandri Magni epistulae ne désigne pas Alexande le Grand, auteur d’epistulae, mais des epistulae dont l’auteur est Alexandri Magni – autrement dit, sous cet identifiant est regroupée la correspondance de cet auteur. Nous avons conservé les noms tels qu’ils apparaissaient dans les données que nous utilisons.

Principes méthodologiques

Nous allons formater les données que nous avons récupérées pour qu’elles correspondent aux variables que nous avons décrites, en procédant successivement variable par variable.

Pour chaque section de formatage, nous allons procéder dans l’ordre suivant :

  • Présentation de la variable et du formatage nécessaire
  • Création de fonctions adaptées pour formater la variable convenablement
  • Test des fonctions, sur des données choisies ou une copie intermédiaire de nos données
  • Application des fonctions à nos tableaux de données
  • Corrections supplémentaires, si nécessaire
  • Résumé des données obtenues pour la variable

Cette démarche nous permet d’agir, dans le processus de développement du code source servant à notre analyse, avec flexibilité : nous pourrons notamment réaliser des tests au fur et à mesure que nous ajustons et perfectionnons nos fonctions de formatage, dans un aller-retour entre section de tests et section de création de fonctions.

Il y aura ainsi cinq parties :

  1. Récupération de la liste des auteurs (depuis le données Perseus)
  2. Formatage des dates (récupérées à l’étape 1)
  3. Formatage des lieux (récupérés à l’étape 1)
  4. Adjonction des genres littéraires (depuis les données CLTK)
  5. Formatages supplémentaires finaux

Pour finir, la section conclusive contiendra l’ensemble des données ainsi obtenues.

1.1. Des œuvres aux auteurs

Puisque les données récupérées depuis le tableur du projet Perseus consistent en une liste d’œuvres, nous devons en faire une liste d’auteurs, en récupérant les données qui nous intéressent.

On conserve, pour chaque auteur, les variables suivantes :

Description Nom dans notre tableau Nom dans le tableau original
nom name TLG / PHI AUTHOR NAME
identifiant code TLG / PHI #
lieu place Location
date d’activité date_active Century/Dates Active
date “de départ” ou de naissance date_begin Begin Date/Birth Year
date “de fin” ou de mort date_end End Date/Death Year

Pour la date d’activité, il s’agit le plus souvent de siècles, formatés comme des années multiples de 100 (eg. “100 CE” correspond au premier siècle). Pour les dates de début ou de fin, il s’agit d’années ou de siècles (formatés alors comme précédemment).

# We will compute the authors dataframes from the works dataframes.
# Didactic demo code: selecting and renaming columns.
tlg_authors_df <-
  tlg_works_raw_df %>%
  transmute(
    code = `TLG#`,
    name = `TLG AUTHOR NAME`,
    place = `Location`,
    date_active = `Century/Dates Active`,
    date_begin = `Begin Date/Birth Year`,
    date_end = `End Date/Death Year`
  )

Fonctions et application

# Since we will be doing exactly the same operations on both works list,
# we will use functions (to avoid hurtful copy-pasting, which is inconvenient for code modifications).
# Hopefully, column names are almost the same in both retrieved documents.
# Passing column names through a function is not obvious,
# but it's possible if we use what is called quosures.
# @see https://github.com/r-lib/rlang/issues/116
# @see https://stackoverflow.com/questions/48062213/dplyr-using-column-names-as-function-arguments

#' Extract authors from raw works dataframe.
#' @param works_raw_df Dataframe. Works as dataframe, extracted from data.
#' @param specific_filling String. String that is specific to the columns names in the data.
#' e.g. "PHI" is used in the latin works dataframe for naming some columns,
#' whereas "TLG" is prefered in the greek one.
#' @return Dataframe. Authors as dataframe.
extract_authors <- function(works_raw_df, specific_filling) {
  # Compute some column names that are specific to the given data frame.
  code_col_name <- paste0(specific_filling,"#")
  author_col_name <- paste0(specific_filling," AUTHOR NAME")

  # Build the data frame.
  authors_df <-
    # 1. Keep only the columns we need from raw data and rename them.
    works_raw_df %>%
    transmute(
      code = !!sym(code_col_name),    # Identifiant de l'auteur
      name = !!sym(author_col_name),  # Nom de l'auteur
      place = `Location`,
      date_active = `Century/Dates Active`,
      date_begin = `Begin Date/Birth Year`,
      date_end = `End Date/Death Year`
    ) %>%
    # 2. Drop trailing carriage returns that mess things up.
    mutate_all(~ str_replace_all(., "\n$", "")) %>%
    # 3. Trim all.
    mutate_all(~ str_trim(.)) %>%
    # 4. Keep only the first four digits from the code,
    # and parse it to a numerical value for further analysis.
    # Only the first four are relevant to the author,
    # other trailing characters in the code
    # can characterize the work, for instance
    # (remember it's a list of works we have at the beginning).
    # Beware: When numbers are <1000, they are not always padded on the right.
    mutate(
      code = code %>%
        str_extract("^\\d{1,4}") %>%
        parse_number()
    ) %>%
    # 5. Select only one row per unique code,
    # that is to say: keep only one row per author,
    # instead of one row per work.
    # We could have used the author's name, but
    # 1) using the code drops the authors who do not have a code,
    # and since we want to analyze codes,
    # we have no use of authors that do not have a code;
    # 2) using the name would keep only one individual for hononyms instead of several.
    # rq: It keeps one row with 'NA' as code, we will remove it hereafter.
    distinct(code, .keep_all = TRUE) %>%
    # 6. Sort by code.
    arrange(code) %>%
    # 7. Replace NA-equivalent values to proper NA.
    mutate_all(~ replace(., . %in% na_variants, NA)) %>%
    # 8. Drop rows that don't have any code.
    drop_na(code)

  # Return the data frame.
  return(authors_df)
}

phi_authors_df <- extract_authors(phi_works_raw_df, "PHI")
tlg_authors_df <- extract_authors(tlg_works_raw_df, "TLG")

Corrections d’erreurs manuelles

Nous n’avons pas vérifié de manière systématique les erreurs qui peuvent être présentes dans les données que nous avons récupérées, nous corrigeons seulement celles qui relèvent de valeurs aberrantes immédiatement visibles lors de nos formatages ultérieurs, manifestement dues à des erreurs de frappe, comme par exemple l’indication de “Rhodes” comme siècle d’activité.

# Some manual corrections of errors in the data.
# The transformations are as follows:
# - place <-> date_active, for 2353 (instead of "500 BCE" as place and "Rhodes" as date)
# - place -> date_active, for 1784 (instead of "400 BCE" as place)
# - date_active -> NA, for 2514 (instead of "Rome, Italy")
# - date_end -> "495 BCE/478 BCE", for 0237 (instead of "CE" when the other two are "BCE")
tmp_place_2353 <-
  tlg_authors_df %>%
  filter(code == 2353) %>%
  pull(date_active)
tlg_authors_df <- tlg_authors_df %>%
  mutate(
    date_active = case_when(
      code == 1784 | code == 2353 ~ place,
      code == 2514 ~ NA_character_,
      TRUE ~ date_active
    ),
    place = case_when(
      code == 1784 ~ NA_character_,
      code == 2353 ~ tmp_place_2353,
      TRUE ~ place
    ),
    date_end = case_when(
      code == 237 ~ "495 BCE/478 BCE",
      TRUE ~ date_end
    )
  )
# Remove variables that are useless in the future.
remove(tmp_place_2353)

1.2. Formatage des dates

Les dates extraites de nos données d’origine sont peu mobilisables dans des analyses statistiques, elles manquent de cohérence et sont difficilement interprétables programmatiquement, ne correspondant à aucun format structuré.

Nous allons donc les formater convenablement.

Les données d’origine sont textuelles et contiennent plusieurs erreurs et irrégularités. Par conséquent, le travail d’encodage à faire est important.

Nous allons commencer par établir les expressions régulières : d’abord celles qui semblent correspondre plus ou moins aux données de départ, puis celles auxquelles nous souhaitons faire strictement correspondre les données “mises au propre”.

Une fois cet objectif déterminé, nous devrons tout d’abord re-formater les dates en restant dans le domaine des chaînes de caractères, de telle sorte qu’elles correspondent scrupuleusement à l’expression régulière finale que nous souhaitons, puis, une fois ce travail accompli, nous pourrons les convertir en nombre facilement.

L’expression régulière finale aura la forme suivante :

"(ante|post)?(\\d{1,4})(ce|bce)(\\?)?"

ante 200 bce ?

avant / après la date considérée
année
avant / de notre ère
indicateur de date incertaine

La date peut également être un intervalle : ce sont alors deux dates formatées comme ci-dessus liées par un tiret.

Nous ne retiendrons néanmoins sous la forme numérique, pour chaque date, que les deux parties centrales, à savoir l’année et si cela est avant notre ère ou de notre ère. “ante200bce?” donnera donc “-200”.

Comme nous l’avons déjà évoqué, lorsque nous seront face à un intervalle, nous prendrons la moyenne des extrémités : “100ce-200ce” donne “150”.

Remarques techniques introductives

# We will need a date parser.

# We could extract the first (most-left) match from the sequence of digits,
# which would be good enough,
# but this does not deal with BCE/CE, nor does it assure data correctness.
# So we will parse things in a neatlier way.
# Here we have to deal with the date before common era (BCE) and within common era (CE).

# This causes a few problems
# since most specifications and packages do not deal with this natively:

# - Timestamps usually start at 1970-01-01.
# Dates before are stored as negative values, eg.
lubridate::ymd_hms("1969-12-31T23:59:59") # == -1

# - ISO 8601 year starts at 0000-01-01 which is the 1st January of 1 BCE.
# @see https://en.wikipedia.org/wiki/ISO_8601

# Reminder: There is no such thing as year zero.
# @see https://en.wikipedia.org/wiki/Year_zero
# Although, there are some "0 CE" and "0 BCE" in our data, which is not clear.
# A few remarks about the lubridate package.

# The lubridate package
# - Does not handle BCE date natively
# - Will not be able to match our data as raw values
# (that have intervals and CE/BCE specifications)
# @see https://lubridate.tidyverse.org/
# @see https://raw.githubusercontent.com/rstudio/cheatsheets/master/lubridate.pdf
# @see https://github.com/tidyverse/lubridate/issues/2

# If we want to deal with BCE date anyway, we could do something such as:
lubridate::ymd("0000-01-01") - lubridate::years(1) # == "-001-01-01"
# @WARN: Since "0000-01-01" is 1 BCE, "-0001-01-01" would be 2 BCE.
# We could write a helper function to retrieve correct dates from this,
# also taking into account months, days, etc., that we do not need here.

On prépare les données qui nous serviront pour nos tests.

# Test sample from the data,
# to build regex fitted for most common cases.
test_dates <- c(
  "400 BCE",
  "200 BCE?",
  "10 CE",
  "01 CE",
  "200 CE",
  "200 CE?",
  "1050 CE",
  "ante 200 CE",
  "Ante 100 CE",
  "post 200 CE",
  "90 CE/95 CE",
  "100 BCE-0 CE",
  "600 BCE-500 BCE",
  "100 CE-200 CE?",
  "100 BCE-100 CE",
  "284 BCE/275 BCE",
  "1100 CE-1200 CE",
  "ante 100 CE-200 CE",
  # Writing errors?
  "500 BCE-",
  "200 - 400 CE"
)

# Every date in the data, to functions against them.
test_cols_dates <- c(
  tlg_authors_df$date_active,
  tlg_authors_df$date_begin,
  tlg_authors_df$date_end,
  phi_authors_df$date_active,
  phi_authors_df$date_begin,
  phi_authors_df$date_end
)

Trouver l’expression régulière adaptée

# Regular expressions.
# rq: The (?i) flag for case-insensitivity works with the stringr package.
# It may end up duplicated here, but it does not seem to matter.

# 1. Loose regular expressions,
# avoiding any re-writing of data.
date_loose_single_regex <- "(?i)((ante|post|pre|before)? ?\\d{1,4} ?(CE|BCE)\\??-?)"
date_loose_regex <- paste0(date_loose_single_regex," ?((-|/) ?",date_loose_single_regex,")?")

# 2. Strict regular expressions,
# that requires pre-formatting of data,
# such as whitespaces removing and terms homogeneity.
date_single_regex <- "(ante|post)?(\\d{1,4})(ce|bce)(\\?)?"
# Capturing groups (starting at 2, in columns of the matrix resulting from`match()`):
# - 2-5 are for left-side (start of date interval)
# - 6-9 are for right-side (end of date interval)
# - 2, 6: "ante" or "post" (optional)
# - 3, 7: year as number
# - 4, 8: "ce" or "bce"
# - 5, 9: whether it is an approximation (optional)
date_regex <- paste0(date_single_regex,"(?:-",date_single_regex,")?")
# Test to adjust regex gradually, we look at what does not pass the regex.
test_dates %>% str_subset(paste0("^",date_loose_regex,"$"), negate = TRUE)
test_cols_dates %>%
  setdiff(na_variants) %>%
  str_subset(paste0("^",date_loose_regex,"$"), negate = TRUE)

Après plusieurs essais, on comprend qu’une expression régulière ne va pas suffire pour récupérer les informations depuis les données d’origine : un formatage supplémentaire préalable se révèle nécessaire.

Formater les chaînes de caractères

#' Format dates from a string vector so they match our strict regex.
#' @param str_v String vector containing date to format.
#' @return String vector with dates formatted.
format_dates <- function(str_v) {
  res_str_v <-
    str_v %>%
    # 1. Lowercase.
    str_to_lower() %>%
    # 2. Remove every whitespaces, as they are meaningless.
    str_replace_all(" ", "") %>%
    # 3. Replace irregular values to homogenize.
    str_replace_all(c(
      "/" = "-",
      "pre|before" = "ante"
    )) %>%
    # 4. Fix some writing errors.
    # rq: Here we temporary use whitespaces
    # as they are nicer than lookarounds, eg. "(?<=\d)bcw(?=-|$)"
    str_replace_all("([a-z]+)", " \\1 ") %>%
    str_replace_all(c(
      " e " = "ce",
      " cer " = "ce",
      " be " = "bce",
      " bc " = "bce",
      " bcw " = "bce",
      " bcebce " = "bce"
    )) %>%
    str_replace_all(" ", "") %>%
    # 5. Remove trailing "-".
    str_replace_all("-$", "") %>%
    # 6. Add ce/bce on the left side when it is missing.
    # @WARN: Here, we use lookahead to copy the right side to the left side,
    # as if it were a common factor.
    # In our data things seem to be doing fine,
    # but this method does not handle the hypothetical case
    # where left-side would be BCE and right CE.
    # In this case, we would know that,
    # considering left comes chronologically before right:
    # - If right is BCE, then left is also BCE;
    # eg. 200-100bce must be 200bce-100bce
    # - If right is CE, then left is BCE
    # if digits on the left are greater than the ones on the right;
    # eg. 200-100ce must be 200bce-100ce
    # - If there are not, we cannot be sure if left is CE or BCE.
    # eg. 50-100ce cannot be determined
    # So we would need to match, parse to number, and compare each side.
    str_replace_all("(\\d)(?=-\\d+(bce|ce))", "\\1\\2")
  # 7. Delete elements that still don't pass the regex,
  # there are not valid dates and we cannot make them fit into one.
  # In our data, we are left with "rhodes" and "rome,italy".
  # They are not dates. We fix those two in previous sections of the document.
  res_str_v <- res_str_v %>%
    str_detect(paste0("^",date_regex,"$")) %>%
    if_else(res_str_v, NA_character_)

  return(res_str_v)
}
# Test to improve formatting gradually, we look at what does not pass the regex.
test_cols_dates %>%
  format_dates() %>%
  str_subset(paste0("^",date_regex,"$"), negate = TRUE)

Convertir les caractères en nombres

#' Helper function.
#' Convert a side of the interval into a number.
#' @param match String vector. Relevant portion of a match from convert_dates()
#' @return Number, date as number
hlp_convert_single_date <- function(match) {
  is_bce <- if_else(match[, 3] == "bce", TRUE, FALSE)
  number <- parse_number(match[, 2])
  number <- if_else(is_bce, -number, number)
  return(number)
}
#' Convert dates into a number, which is the year.
#' CE years are positive values, BCE years are negative values.
#' If the date includes an interval, take the mean of the interval.
#' @param str_v String vector containing date to convert.
#' @return Number vector with converted dates.
convert_dates <- function(str_v) {
  match <- str_match(str_v, date_regex)
  left_number <- hlp_convert_single_date(match[, 2:5])
  right_number <- hlp_convert_single_date(match[, 6:9])
  res_number <- map2_dbl(
    left_number,
    right_number,
    ~ mean(c(.x, .y), na.rm = TRUE)
  )
  return(res_number)
}
test_cols_dates %>%
  format_dates() %>%
  convert_dates()

Application aux données

#' Parse dates from a dataframe.
#' @param df Dataframe containing date columns to parse.
#' @return Dataframe with dates parsed.
#' @see https://stackoverflow.com/questions/45947787/create-new-variables-with-mutate-at-while-keeping-the-original-ones
parse_dates_df <- function(df) {
  # Columns that we will compute on
  cols <- c("date_active", "date_begin", "date_end")

  res_df <-
    df %>%
    # 1. Apply the functions to every columns we selected.
    mutate(across(
      .cols = all_of(cols),
      .fns = list(
        str = format_dates,
        num = ~ format_dates(.) %>% convert_dates()
      ),
      .names = "{col}_{fn}"
    )) %>%
    # 2. Drop original colums to replace them with their numeric equivalent
    select(-all_of(cols)) %>%
    rename_at(
      paste0(cols,"_num"),
      ~ cols
    ) %>%
    # 3. Regroup columns by type
    relocate(all_of(cols), .before = "date_active_str")

  return(res_df)
}

phi_authors_df <- phi_authors_df %>%
  parse_dates_df()
tlg_authors_df <- tlg_authors_df %>%
  parse_dates_df()

Résumé des dates obtenues

# Beware, the code writing is not great here,
# it has been done quickly.
# To improve, one could look at dyplr::summarise(), or skimr
#' @param df Dataframe.
#' @return NULL. It prints the summary.
print_date_summary <- function(df) {
  tmp_cols <- list(
      df$date_active,
      df$date_begin,
      df$date_end
    ) %>%
    transpose()
  tibble(
    col_name = c("date_active", "date_begin", "date_end"),
    min = pmap_dbl(tmp_cols, min, na.rm = TRUE),
    max = pmap_dbl(tmp_cols, max, na.rm = TRUE)
  )
}

Auteurs latins
print_date_summary(phi_authors_df)

Les auteurs latins que nous avons se répartissent, globalement, du VIe siècle avant notre ère, au VIe siècle de notre ère.


Auteurs grecs
print_date_summary(tlg_authors_df)

Les auteurs grecs que nous avons se répartissent, globalement, du VIIIe siècle avant notre ère, au XVIe siècle de notre ère.

1.3. Formatage des lieux

Pour s’assurer de l’homogénéité des données, tout en gagnant en généralité, nous n’allons garder en matière de lieu que le pays, en laissant de côté des indications plus précises comme la ville. Nous ne gardons également arbitrairement qu’un seul pays lorsque plusieurs sont indiqués.

#' Format places.
#' Only the most-left string, uninterrupted by a comma, is kept.
#' @param df Dataframe
#' @return Dataframe
format_places_df <- function(df) {
  res_df <-
    df %>%
    rowwise() %>%
    mutate(
      place = place %>%
        # 1. Split by comma or similar signs that are also used.
        # Comma and slash are meaningful,
        # but dots or double backslashes seem to be mistakes.
        str_split( ",|/|\\.|\\\\") %>%
        # 2. Keep only the last part
        unlist() %>%
        last() %>%
        # 3. Clean the result for homogeneity
        str_trim() %>%
        str_to_title() %>%
        str_replace_all("\\?", "") %>%
        # 4. Fix some writing errors.
        str_replace_all(c(
          "Liby$" = "Libya",
          "Cyrpus" = "Cyprus"
        ))
    ) %>%
    ungroup()
  return(res_df)
}
# Check that final places are unique.
test_places <- function(df) {
  df %>%
    format_places_df() %>%
    distinct(place) %>%
    arrange(place) %>%
    pull(place)
}
test_places(phi_authors_df)
test_places(tlg_authors_df)
phi_authors_df <- format_places_df(phi_authors_df)
tlg_authors_df <- format_places_df(tlg_authors_df)

Résumé des lieux obtenus


Auteurs latins
phi_authors_df %>%
  distinct(place) %>%
  arrange(place) %>%
  pull() %>%
  print_vector()
Africa Algeria Egypt France Italy Lebanon Libya North Africa Spain Tunisia Turkey
phi_authors_df %>%
  summarise(
    n = n(),
    na_n = sum(is.na(place)),
    na_rate = round(na_n / n, 3)
  )

Auteurs grecs
tlg_authors_df %>%
  distinct(place) %>%
  arrange(place) %>%
  pull() %>%
  print_vector(8)
Albania Anatolia Armenia Bulgaria Cous Crete Cyprus Delos
Egypt Elaita Ephesos Epirus France Greece Iasensis Incerta
Ionia Iran Iraq Israel Italy Jordan Lebanon Lesbos
Libya Lydia Macedonia Manesium Mauretania Mendesicus Mytilene Olynthus
Palestine Pontus Euxinus Rhodes Romania Rome Sardianus Scythia Sicily
Sicyon Syria Syrian Antioch Thrace Tunisia Turkey Ukraine
tlg_authors_df %>%
  summarise(
    n = n(),
    na_n = sum(is.na(place)),
    na_rate = round(na_n / n, 3)
  )

1.4. Adjonction des genres

On ajoute finalement les genres, depuis les données du CLTK. Lorsqu’il y aura plusieurs genres pour un même auteur, on ne conservera que le premier genre dans l’ordre alphabétique.

tmp_tlg_epithets_df <-
  tlg_epithets_raw_df %>%
  unnest(cols = code) %>%
  mutate(code = code %>%
    unlist() %>%
    parse_number()
  ) %>%
  distinct(code, .keep_all = TRUE)
tlg_authors_df <- tlg_authors_df %>%
  left_join(tmp_tlg_epithets_df, by = "code") %>%
  relocate(genre, .after = name)
remove(tmp_tlg_epithets_df)

Résumé des genres obtenus

tlg_authors_df %>%
  distinct(genre) %>%
  arrange(genre) %>%
  pull() %>%
  print_vector(6)
Alchemistae Apologetici Astrologici Astronomici Atticistae Biographi
Bucolici Choliambographi Chronographi Comici Doxographi Elegiaci
Epici/-ae Epigrammatici/-ae Epistolographi Geographi Geometri Gnomici
Gnostici Grammatici Historici/-ae Iambici Lexicographi Lyrici/-ae
Mathematici Mechanici Medici Mimographi Musici Mythographi
Nomographi Onirocritici Oratores Paradoxographi Parodii Paroemiographi
Periegetae Philologi Philosophici/-ae Poetae Poetae Didactici Poetae Medici
Poetae Philosophi Polyhistorici Rhetorici Scriptores Ecclesiastici Scriptores Erotici Scriptores Fabularum
Sophistae Tactici Theologici Tragici

Les données obtenues directement depuis le fichier du CLTK paraissent ne pas comporter d’irrégularités et donc ne pas nécessiter de nettoyage supplémentaire.

tlg_authors_df %>%
  summarise(
    n = n(),
    na_n = sum(is.na(genre)),
    na_rate = round(na_n / n, 3)
  )
tlg_authors_df %>% slice(31:40)

Notons néanmoins qu’il aurait été plus efficace de récupérer l’information des genres directement sur le nom des auteurs : en calculant les valeurs manquantes, on voit qu’il nous en manque plus d’un tiers, et en consultant le contenu des tableaux (ci-dessus un extrait), on s’aperçoit que bien souvent l’épithète qui apparaît pourtant dans le nom n’apparaît pas dans la colonne générée à partir des données du CLTK.

1.5. Formatages supplémentaires

Pour terminer et faciliter les analyses graphiques suivantes, nous allons créer deux nouvelles variables :

  • l’initiale : pour éviter d’avoir à traiter des milliers de noms d’auteurs alors que nous nous intéresserons à un possible classement alphabétique, nous pourrons ainsi ne retenir que leur initiale. Cela nous permettra également d’afficher des couleurs en fonction des initiales, celles-ci constituant une variable catégorielle ;

  • la date : on prendra arbitrairement le plus souvent le siècle d’activité comme date de référence, d’où nous en dupliquons la colonne pour y accéder plus facilement.

De plus, nous supprimons les caractères indésirables au début du nom des auteurs, pour être sûrs de récupérer l’initiale correctement et d’être conformes à l’ordre alphabétique.

# Nettoyage de parenthèses diverses pour le fichier TLG
tlg_authors_df$name <- gsub("(<|\\[|\\()", "", tlg_authors_df$name)

# Création d'une colonne des initiales des auteurs
tlg_authors_df$init <- substring(tlg_authors_df$name,1,1)
phi_authors_df$init <- substring(phi_authors_df$name,1,1)

# Réorganisation de l'ordre des colonnes
tlg_authors_df <- tlg_authors_df %>%
  relocate(init, .before = name)
phi_authors_df <- phi_authors_df %>%
  relocate(init, .before = name)

# Ajout d'une colonne "date" qui copie "date_active", par commodité
tlg_authors_df <- tlg_authors_df %>%
  mutate(date = date_active, .before =  date_active)
phi_authors_df <- phi_authors_df %>%
  mutate(date = date_active, .before =  date_active)

Données finales obtenues

Pour savoir plus précisément ce à quoi correspondent chacune des variables obtenues, rendez-vous au début de la section !


Auteurs latins

phi_authors_df
skim(phi_authors_df)
Data summary
Name phi_authors_df
Number of rows 358
Number of columns 11
_______________________
Column type frequency:
character 6
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
init 12 0.97 1 1 0 19 0
name 12 0.97 5 60 0 346 0
place 100 0.72 5 12 0 11 0
date_active_str 77 0.78 5 14 0 27 0
date_begin_str 170 0.53 3 13 0 121 0
date_end_str 156 0.56 3 13 0 136 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
code 0 1.00 855.19 1061.21 2 445.25 643 1013.25 9969 ▇▁▁▁▁
date 77 0.78 -21.85 174.43 -550 -150.00 -100 100.00 550 ▁▅▇▂▁
date_active 77 0.78 -21.85 174.43 -550 -150.00 -100 100.00 550 ▁▅▇▂▁
date_begin 170 0.53 -35.12 146.09 -529 -116.50 -75 39.62 483 ▁▃▇▂▁
date_end 156 0.56 23.72 151.75 -430 -67.00 -11 96.50 565 ▁▇▇▂▁

Auteurs grecs

tlg_authors_df
skim(tlg_authors_df)
Data summary
Name tlg_authors_df
Number of rows 2176
Number of columns 12
_______________________
Column type frequency:
character 7
numeric 5
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
init 40 0.98 1 1 0 24 0
name 40 0.98 4 65 0 2033 0
genre 860 0.60 6 24 0 52 0
place 701 0.68 4 14 0 47 0
date_active_str 175 0.92 4 15 0 110 0
date_begin_str 930 0.57 3 13 0 343 0
date_end_str 914 0.58 3 13 0 361 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
code 0 1.00 1565.75 1250.89 1 593.75 1425.5 2186.25 9023 ▇▃▁▁▁
date 175 0.92 -56.06 389.59 -800 -350.00 -125.0 200.00 1550 ▇▇▆▁▁
date_active 175 0.92 -56.06 389.59 -800 -350.00 -125.0 200.00 1550 ▇▇▆▁▁
date_begin 930 0.57 -96.66 378.54 -800 -399.00 -199.0 116.50 1465 ▆▇▃▁▁
date_end 914 0.58 -6.50 377.31 -680 -300.00 -100.0 200.00 1535 ▇▇▃▁▁

2. Analyses graphiques

Pour trouver les logiques internes de classement, nous allons procéder progressivement, en analysant successivement les différentes variables en fonction de la variable à expliquer, l’identifiant.

Nous commencerons par analyser les variables deux à deux, en projetant les auteurs selon un nuage de points. L’identifiant, variable à expliquer, sera systématiquement projeté en abscisse, et la variable potentiellement explicative en ordonnée.

Puis nous chercherons à saisir des sous-logiques internes en ajoutant une troisième variable, ce qui correspond à une “troisième dimension” sur nos graphiques, que nous matérialiserons par de la couleur.

Si nécessaire, au fil de nos analyses, nous pourrons revenir en “deux dimensions” si cela paraît pertinent – éventuellement en colorant une des dimensions pour davantage de clarté visuelle –, par exemple sur une séquence particulière – car il se pourrait bien que nous découvrions l’existence de “séquences” particulières…

À chaque fois, on analysera les auteurs grecs, puis les auteurs latins. Au fur et à mesure, on saisira les logiques sous-jacentes aux classifications TLG et PHI.

Analyses en deux dimensions

2.1. Les identifiants par les noms

La classification qui paraîtrait la plus intuitive est celle de l’ordre alphabétique. Voyons donc si les codes sont corrélés ou non aux noms des auteurs projetés par ordre alphabétique.


Auteurs grecs

tlg_authors_df %>%
  ggplot(aes(code, fct_reorder(name, desc(name))))  +
  geom_point() +
  labs(title = "Identifiants TLG et noms",  x = "code", y = "name")

Ce premier graphique présente un premier problème : les données sont très nombreuses, si bien que les résultats sont peu clairs. On observe néanmoins que la majorité des codes se trouvent entre 0 et 2500, et la grande majorité entre 0 et 5000. On pourrait donc se concentrer sur cette portion, et masquer les noms de sorte à ce que le graphique puisse davantage s’étaler.

tlg_authors_df %>%
  filter(code < 5000) %>%
 ggplot(aes(code, fct_reorder(name, desc(name)))) +
  geom_point() +
  labs(title = "Identifiants TLG et noms (0-5000)", x = "code", y = "name") +
  scale_x_continuous(breaks = round(seq(0, 5000, by = 200),1)) +
  theme(
    axis.text.y = element_blank(),
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
    panel.grid.major.x = element_line(size = 0.5, color = "grey")
  )

On observe assez clairement des lignes droites. Cela ressemble à des séries cohérentes de noms classés par ordre alphabétique sur certaines portions. Il faudrait donc découper les codes TLG en plusieurs séquences successives pour en analyser la logique interne.

On observe notamment que les droites qui apparaissent se situent avant le code 1800 : il semblerait donc que les codes ultérieurs obéissent à une autre logique que la logique alphabétique, alors qu’avant 1800 il y aurait pu avoir des “ajouts par vagues successives” à la liste des identifiants, chaque vague étant par ordre alphabétique.

Intéressons-nous plus en détail à la séquence avant 1800.

# Première tentative de créer un vecteur à partir des codes,
# pour les diviser en plusieurs séquences,
# et en tirer des informations plus facilement.
#code_authors_tlg <-
#  as_tibble(tlg_authors_df) %>%
#  slice(code) %>%
#  unlist(., use.names = FALSE)
#split(code_authors_tlg, 1:2545)

tlg_authors_df %>%
  filter(code < 1800) %>%
  ggplot(aes(code, fct_reorder(name, desc(name)))) +
  geom_point() +
  labs(title = "Identifiants TLG et noms (0-1800)", x = "code", y = "name") +
  scale_x_continuous(breaks = round(seq(0, 1800, by = 100),1)) +
  theme(
    axis.text.y = element_blank(),
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
    panel.grid.major.x = element_line(size = 0.5, color = "grey")
  )

  labs(title = "Identifiants TLG et noms (0-5000)")
$title
[1] "Identifiants TLG et noms (0-5000)"

attr(,"class")
[1] "labels"

On observe :

  • Une séquence évidente de ~1100 à ~1800. Elle va de presque le début de l’alphabet, à la fin de l’alphabet ;
  • Deux séquences, de ~390 à ~520, et de ~750 à ~1120, qui s’étendent tout le long de l’alphabet ;
  • Une séquence de ~100 à ~200 qui s’arrête vers le milieu de l’alphabet ;
  • Une petite séquence concentrée au début de l’alphabet entre ~650 et ~750. Dans l’alphabet (en ordonnées), elle semble s’arrêter proche de la valeur où la longue traînée de ~1100 à ~1800 commence.

De plus, on remarque plusieurs éléments :

  • Même sur cette portion, il y a plusieurs séquences d’identifiants qui paraissent ne pas suivre la logique alphabétique (en particulier entre 0 et 100, entre 200 et 400, entre 520 et 650). Ces séquences pourraient suivre une autre logique, ou bien ne correspondre à rien d’identifiable facilement – il pourrait s’agir d’une attribution “au hasard”, ou correspondre à une entrée des identifiants “au fil de l’eau” sans logique systématique pré-établie, par exemple au fur et à mesure que de nouveaux auteurs enrichissaient le corpus TLG.

  • Même sur les séquences où l’ordre alphabétique paraît significatif, il y a parfois quelques “points aberrants”, éloignés de la droite qui se dessine : ils semblent ne pas suivre la logique de la séquence d’identifiants dans laquelle ils s’insèrent. Le plus vraisemblable, c’est alors que le nom que nous avons dans nos données ne corresponde pas au nom qui a été utilisé pour attribuer l’identifiant – ou alors, lorsque le nom est composé de plusieurs termes, que celui positionné en premier dans nos données ne soit pas celui qui ait servi pour l’indexation alphabétique de l’auteur, comme dans le cas d’un prénom suivi d’un patronyme.

  • Enfin, on remarque un aspect qui pouvait déjà être aisément constaté auparavant : il existe des “identifiants” manquants, auxquels aucun auteur ne correspond. Ce phénomène semble apparaître également au sein même des séries alphabétiques. Par exemple :

tlg_authors_df %>% filter(code >= 840 & code <= 850)

On observe ici qu’entre les identifiants 840 et 850, on ne trouve en fait que deux identifiants : le 845 et le 848. Les identifiants 840, 841, 842, 843, 844, 846, 847, 849 et 850 sont “manquants”.

Ce dernier phénomène ne paraît pas évident à expliquer. Nous voyons plusieurs hypothèses qui peuvent être complémentaires. Il pourrait s’agir de séquences programmées, la plage leur étant alors réservée, mais finalement non réalisées, ou réalisées uniquement partiellement, par exemple du fait de corpus non prêts dans les temps. Si les sauts existaient au moment même de l’attribution, il se pourrait autrement qu’ils relèvent d’erreurs ou d’ajouts intempestifs au sein d’une série plus longue. On pourrait sinon imaginer que ces “sauts” pourraient aussi être le résultat de manipulations ultérieures : les auteurs qui possédaient ces identifiants auraient été “réattribués”, ou même tout simplement supprimés, pour une raison ou pour une autre. Pour autant cette hypothèse semble peu probable, dans la mesure où la modification de l’identifiant d’un corpus publié poserait des problèmes techniques de réattribution en chaîne pour son référencement.

Ces hypothèses demeurent spéculatives, dans la mesure où nous ne disposons pas de l’historique de constitution de ces bases de données. Une variable comme la date d’entrée du corpus dans la bibliothèque pourrait ici nous éclairer.

Auteurs latins

Passons aux auteurs latins.

phi_authors_df %>%
  ggplot(aes(code, fct_reorder(name, desc(name)))) +
  geom_point() +
  labs(title = "Identifiants PHI et noms",  x = "code", y = "name")

On voit que la grande majorité des identifiants sont inférieurs à 2500 : concentrons-nous sur cette portion.

phi_authors_df %>%
  filter(code < 2500) %>%
  ggplot(aes(code, fct_reorder(name, desc(name)))) +
  geom_point() +
  labs(title = "Identifiants PHI et noms (0-2500)", x = "code", y = "name") +
  scale_x_continuous(breaks = round(seq(0, 2500, by = 100),1)) +
  theme(
    axis.text.y = element_blank(),
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
    panel.grid.major.x = element_line(size = 0.5, color = "grey")
  )

Contrairement aux auteurs grecs du TLG, les résultats paraissent cette fois beaucoup moins évidents, et la corrélation entre l’identifiant et la place du nom dans l’ordre alphabétique est un peu douteuse. Tout au plus, on pourrait penser qu’il existe une petite tendance de ~400 à ~700, voire entre ~800 et ~1050. Mais il semblerait que la classification obéisse essentiellement à d’autres logiques, que nous allons désormais tenter d’explorer.

2.2. Les identifiants par les dates

Après l’ordre alphabétique, une autre classification qui paraîtrait assez intuitive est la classification chronologique par dates. Nous allons donc voir dans quelle mesure les codes TLG et PHI sont explicables par l’époque des auteurs, puis nous croiserons ensuite, dans la partie suivante, la date avec d’autres variables.


Auteurs grecs

# Première étude en noir et blanc
ggplot(tlg_authors_df, aes(x = code, y = date)) +
  geom_point() +
  labs(title = "Identifiants TLG et dates")

À première vue, la variable “date” n’explique pas la variable “code” du TLG. Les 2600 premiers identifiants se concentrent avant 2500, et l’on constate quelques “cheminées” aux environs de 3000, 4000 et 9000 concernant surtout les auteurs d’après 500 CE.


Auteurs latins

ggplot(phi_authors_df, aes(x = code, y = date)) +
  geom_point() +
  labs(title = "Identifiants PHI et dates")

Concernant les auteurs latins, on semble apercevoir pour le code PHI une corrélation assez forte entre la progression des identifiants et celle des dates. Un identifiant culmine à 9500 et trois autres auteurs dépassant 9000 ne sont pas datés.

cor.test(phi_authors_df$code, phi_authors_df$date)

    Pearson's product-moment correlation

data:  phi_authors_df$code and phi_authors_df$date
t = 16.996, df = 279, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.6504864 0.7662757
sample estimates:
      cor 
0.7132127 

Cette corrélation entre ces deux variables, identifiant et date, paraît statistiquement vérifiée.

Regardons de plus près la séquence de 0 à 3000.

tmp_phi_3000 <-
  phi_authors_df %>%
  filter(code < 3000)
cor.test(tmp_phi_3000$code, tmp_phi_3000$date)

    Pearson's product-moment correlation

data:  tmp_phi_3000$code and tmp_phi_3000$date
t = 29.618, df = 278, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.8399880 0.8970016
sample estimates:
      cor 
0.8714067 

La corrélation paraît encore plus forte pour les identifiants inférieurs à 3000. Essayons de modéliser une relation linéaire.

#' Make a linear model, print its infos and components, and plot its equivalent.
#' rq: Here we use `tibble()`, to make quosures work.
#' There may be a neater way.
#' rq: We need to explicitly return things to be printed,
#' otherwise only a table at the end of the function will be printed.
#' Thus, we then need to 'hide' chunk results to avoid printing of raw console output.
#' @see https://stackoverflow.com/questions/42024921/why-does-kable-not-print-when-used-within-a-function-in-rmarkdown
#' @param var String of the variable name to test in the linear model.
#' @param var_strin String to display in the plot name.
#' @return Things to print.
phi_display_lm <- function(var, var_str) {
  data_df <- tmp_phi_3000
  lm_df <-
    tibble(
      lm_components = broom::tidy(lm(code ~ !!sym(var), data_df)),
      lm_infos = broom::glance(lm(code ~ !!sym(var), data_df))
    )
  lm_comps_print <- lm_df %>% pull(lm_components) %>% knit_print()
  lm_infos_print <- lm_df %>% pull(lm_infos) %>% slice_head() %>% knit_print()
  lm_plot <- data_df %>%
    ggplot(aes(x = code, y = !!sym(var))) +
    geom_point() +
    geom_smooth(method = "lm") +
    scale_y_continuous(
      limits = c(-500, 600),
      breaks = seq(-500, 600, by = 100)
    ) +
    labs(title = paste0("Identifiants PHI et ",var_str))
  return(list(
    lm_comps_print,
    lm_infos_print,
    lm_plot
  ))
}
phi_display_lm("date", "dates d'activité")

En y regardant de plus près on voit bien, sur les identifiants entre 0 et 3000, une corrélation linéaire significative sans ambiguïté (\(p\mbox{-}valeur \lll 0.001\)) entre la valeur de l’identifiant et la date, ou le siècle, d’activité : un simple modèle linéaire (\(code_{i} = \beta_{0} + \beta_{1} \times date_{i} + \epsilon_{i}\)) explique ainsi les trois quarts de la variance (\(R^{2} \approx 0.76\)).

Rappelons que nous avons ici utilisé une seule des trois dates qui étaient à notre disposition : voyons la manière dont se distribuent les deux autres.

phi_display_lm("date_begin", "dates de commencement")

phi_display_lm("date_end", "dates de fin")

À partir des seuls calculs statistiques, il ne paraît pas évident de tirer des conclusions. En revanche, du point de vue de l’analyse graphique, les dates de “fin” semblent, au moins autour de l’identifiant 500, former un carré comme si les auteurs morts au cours du premier siècle avant notre ère faisaient tous, ou presque, partie d’une même catégorie. On pourrait encore affiner les analyses de cette catégorisation, sans oublier que les données manquantes sont plus nombreuses pour les dates de “fin” ou de “début” que la date plus générale d’activité (voir la section “Données finales”).

remove(tmp_phi_3000)

Analyses en trois dimensions

D’autres variables interviennent-elles dans la numérotation des codes ? En sus des dates, nous allons examiner trois autres variables : l’initiale du nom – en croisant donc la question de l’ordre alphabétique que nous avons déjà évoquée –, le genre littéraire, ainsi que le lieu. Ces variables seront exprimées par des couleurs.

Les couleurs par défaut de ggplot étant plutôt fades et peu différenciées, rendant la lecture difficile, nous créerons également une palette passant graduellement du rouge au bleu, en passant respectivement par l’orangé, le jaune et le vert (il faut compter près de 26 lettres).

# Création d'une palette de couleurs de type rosace,
# en jouant sur les codes #RRVVBB, chaque chiffre de 0 à F.
couleurs <- c(
  "#990000", "#cc0000", "#ff0000", "#ff3300",
  "#ff6600", "#ff9900", "#ffcc00", "#ffff00",
  "#ccff00", "#99ff00", "#66ff00", "#33ff00",
  "#00ff00", "#00ff33", "#00ff66", "#00ff99",
  "#00ffbb", "#00ffff", "#00ccff", "#0099ff",
  "#0066ff", "#0033ff", "#0000ff", "#0000cc",
  "#000099"
)

2.3. Identifiants, dates et initiales

Nous reprenons les deux graphiques précédents projetant les identifiants selon les dates (TLG et PHI), en colorant cette fois les points selon les initiales des auteurs.


Auteurs grecs

ggplot(tlg_authors_df, aes(x = code, y = date, color = init)) +
  geom_point() +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants TLG, dates et initiales")

De longs traits verticaux de couleurs apparaissent, mais un cadrage est à réaliser, notamment pour les codes entre 1150 et 1800.

ggplot(tlg_authors_df, aes(x = code, y = date, color = init)) +
  geom_point() +
  xlim(1150, 1800) +
  ylim(-750, 500) +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants TLG, dates et initiales (1150-1800)")

Il apparaît clairement que les numéros de code entre 1150 et 1800 suivent les initiales du noms des auteurs grecs. Le graphique suivant examine les codes entre 1800 et 2500. En revanche, la date paraît ne jouer aucune importance : on retrouve, pour chaque même date, des auteurs tout le long de la séquence d’identifiants considérée.

ggplot(tlg_authors_df, aes(x = code, y = date, color = init)) +
  geom_point() +
  xlim(1800, 2500) +
  ylim(-750, 500) +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants TLG, dates et initiales (1800-2500)")

L’observation qui s’applique entre 1150 et 1800 ne se retrouve pas entre 1800 et 2500, même si l’on retrouve quelques lignes ascendantes, peut-être fortuites.

Observons désormais les autres séquences que nous avions distinguées lorsque nous avons projeté les identifiants en fonction des noms.

#' Plot code by date and init,
#' for a sequence between two given values,
#' from `phi_authors_df_nopr`.
#' @param start Number. Code to start with
#' @param end Number. Code to end with.
tlg_plot_code_date_init_seq <- function(start, end) {
  tlg_authors_df %>%
    filter(code >= start, code <= end) %>%
    drop_na(date, init) %>%
    ggplot(aes(x = code, y = date, color = init)) +
    geom_point() +
    #ylim(-600, 300) +
    scale_color_manual(values = couleurs) +
    labs(title = paste0("Identifiants TLG, dates et initiales (",start,"-",end,")"))
}
tlg_plot_code_date_init_seq(100, 200)

tlg_plot_code_date_init_seq(390, 550)

tlg_plot_code_date_init_seq(650, 750)

tlg_plot_code_date_init_seq(750, 1100)

Comme nous l’avions remarqué, il existe en effet une régularité. Néanmoins, les dates ne semblent jouer aucun rôle sur ces séquences, si ce n’est que chaque séquence s’étale plus ou moins dans le temps :

  • la séquence entre 100 et 200 s’étale de -400 à 250
  • la séquence entre 400 et 525 s’étale de -500 à -200 (c’est particulièrement ramassé)
  • la séquence entre 650 et 750 s’étale de -500 à 550
  • la séquence entre 750 et 1100 s’étale de -500 à 250
  • la séquence entre 1150 et 1800 s’étale de -700 à 500 (c’est particulièrement étendu)

Auteurs latins

On applique le principe des points de couleur selon l’initiale pour les auteurs latins.

# Auteurs latins.
ggplot(phi_authors_df, aes(x = code, y = date, color = init)) +
  geom_point() +
  xlim(0, 2500) +
  ylim(-350, 600) +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants PHI, dates et initiales")

Si le code est corrélé à la date, ce qui apparaissait déjà plus haut, le nom ne semble avoir aucun rôle dans la numérotation.

Il nous avait néanmoins semblé que quelque chose comme une suite alphabétique pourrait bien apparaître au moins entre les identifiants 400 et 700. Restreignons donc l’observation plus spécifiquement à cette séquence. Étant donné que cette séquence fait apparaître des auteurs d’une période similaire – le premier siècle avant notre ère –, nous allons pour un instant revenir en deux dimensions en supprimant la variable date et ainsi mieux voir la répartition des noms.

ggplot(phi_authors_df, aes(x = code, y = fct_reorder(name, desc(name)), color = init)) +
  geom_point() +
  xlim(400, 750) +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants PHI et noms (400-750)", x = "code", y = "name")

Une ligne paraît vaguement se distinguer, mais de très nombreux auteurs semblent ne pas entrer dans cette logique. C’est possible car le nom qui apparaît dans notre tableau n’est pas conforme au nom utilisé dans la classification.

On remarque en effet que les noms tels que nous les avons récupérés commencent souvent par le “praenomen”. Il est facile d’ôter les prénoms représentés par une initiale suivie d’un point. On crée pour cela un tableau intermédiaire.

phi_authors_df_nopr <- phi_authors_df
phi_authors_df_nopr$name <- gsub("[A-Z][a-z]{0,2}\\. ", "", phi_authors_df_nopr$name)
phi_authors_df_nopr$init <- substring(phi_authors_df_nopr$name,1,1)

Un travail plus systématique aurait consisté à observer sur le site de PHI ce qui y est considéré comme étant le nom principal de chaque auteur (apparaissant en gras) pour garder celui-ci comme nom de référence. Il aurait été possible de récupérer ces données depuis internet par exemple avec la bibliothèque rvest.

Pour l’heure, nous nous contenterons de cette première mise en forme.

ggplot(phi_authors_df_nopr, aes(x = code, y = date, color = init)) +
  geom_point() +
  xlim(0, 2500) +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants PHI, dates et initiales (sans praenomen)")

Il est difficile de distinguer les choses à ce niveau. De nouveau, revenons à une représentation en deux dimensions en supprimant la variable “date”, puis nous nous focaliserons sur certaines séquences, chacune correspondant à une période.

phi_authors_df_nopr %>%
  filter(code < 2500) %>%
  drop_na(name, init) %>%
  ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = init)) +
  geom_point() +
  scale_color_manual(values = couleurs) +
  labs(title = "Identifiants PHI et noms (sans praenomen)", x = "code", y = "name")

Des lignes apparaissent effectivement bien clairement ! Regardons les séquences de plus près.

#' Plot code by name,
#' for a sequence between two given values,
#' from `phi_authors_df_nopr`.
#' @param start Number. Code to start with
#' @param end Number. Code to end with.
phi_plot_code_name_seq <- function(start, end) {
  phi_authors_df_nopr %>%
    filter(code >= start, code <= end) %>%
    drop_na(name, init) %>%
    ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = init)) +
    geom_point() +
    scale_color_manual(values = couleurs) +
    labs(
      title = paste0("Identifiants PHI et noms (sans praenomen, ",start,"-",end,")"),
      x = "code",
      y = "name"
    ) +
    theme(axis.text.y = element_blank())
}
phi_plot_code_name_seq(0, 200)

phi_plot_code_name_seq(400, 750)

phi_plot_code_name_seq(750, 1200)

phi_plot_code_name_seq(1200, 1400)

Les tendances apparaissent bien avec clarté.

Une dernière manière de représenter ces tendances serait de colorer cette fois non plus les initiales mais les dates : on devrait observer que les différentes séquences sont chacune d’une teinte particulière.

phi_authors_df_nopr %>%
  filter(code < 2500) %>%
  drop_na(name, date) %>%
  ggplot(aes(code, fct_reorder(name, desc(name)), color = date)) +
  geom_point() +
  labs(title = "Identifiants PHI, noms et dates", y = "name") +
  scale_color_gradientn(colors = couleurs) +
  theme(axis.text.y = element_blank())

C’est effectivement ce que l’on observe !

Il semblerait donc que les auteurs latins soient, dans la classification PHI, rangés d’abord par date, et ensuite de manière secondaire, sur chaque période, par ordre alphabétique du nom.

Le nom ne commence alors manifestement pas par le praenomen. Les points aberrants par rapport aux droites qui se dessinent sont vraisemblablement des auteurs pour lesquels le nom que nous avons dans notre tableau ne correspond pas au nom utilisé lors de l’attribution de l’identifiant.

Pour distinguer plus clairement les périodes, nous devrions faire des recherches supplémentaires, afin de savoir précisément selon quel(s) critère(s) certains auteurs sont rattachés à une période et non à la précédente ou à la suivante : s’agit-il du siècle correspondant à la date de naissance ? à la date de mort ? à la période principale de production littéraire ? Ou est-ce un découpage d’un autre ordre, selon des périodes historiques ? Il faudrait pour cela délimiter précisément les séquences – ceci fait, on pourrait s’intéresser aux auteurs situés à leurs extrémités, afin de saisir ce qui fait passer d’une séquence à une autre. La première analyse conduite dans la section “Les identifiants par les dates” inciterait à nous pencher sur le siècle de la date de mort.

Il faut enfin noter que, comme nous l’avons déjà relevé pour les auteurs grecs (voir la section “Les identifiants par les noms”), il existe de nouveau des “trous” dans les séquences ; ces “sauts” dans la numérotation demeurent difficiles à élucider avec les seules données ici à notre disposition.

2.4. Identifiants et genres

Pour les auteurs grecs, la logique de classification nous demeure peu claire. Si certaines séries alphabétiques apparaissent, on ne sait pas pourquoi elles apparaissent dans cet ordre-là, et il existe également des séquences entières qui semblent ne pas correspondre à l’ordre alphabétique ni à l’ordre chronologique.

Essayons donc de chercher une logique, ou des logiques, à partir des genres littéraires.

tlg_authors_df %>%
  filter(code < 5000) %>%
  ggplot(aes(x = code, y = fct_reorder(genre, desc(genre)))) +
  geom_point() +
  labs(title = "Identifiants TLG et genres littéraires", y = "genre")

Un premier graphique en deux dimensions ne donne pas grand-chose : à première vue, chaque genre peut se répartir tout du long de la numérotation.

Supprimons les genres contenant moins de dix auteurs pour y voir plus clair.

tlg_authors_df %>%
  filter(code < 5000) %>%
  group_by(genre) %>%
  mutate(genre_n = n()) %>%
  ungroup() %>%
  filter(genre_n > 10) %>%
  ggplot(aes(x = code, y = fct_reorder(genre, desc(genre)))) +
  geom_point() +
  labs(title = "Identifiants TLG et genres littéraires (plus de dix auteurs)", y = "genre")

À la rigueur, on peut relever que les orateurs sont concentrés au début de la numérotation, et les “Poetae” autour de 2600.

Néanmoins, on a sur ce graphique du mal à distinguer la densité des identifiants et leurs regroupements. Par exemple, on a du mal à faire la différence entre les petites masses très denses et les points uniques ou presque, et on peine à appréhender à quel point certaines lignes sont continues ou non. Ajustons les paramètres graphiques pour discerner les choses plus facilement.

tlg_authors_df %>%
  filter(code < 5000) %>%
  group_by(genre) %>%
  mutate(genre_n = n()) %>%
  ungroup() %>%
  filter(genre_n > 10) %>%
  ggplot(aes(x = code, y = fct_reorder(genre, desc(genre)))) +
  geom_jitter(alpha = 0.2, shape = 16, width = 0, height = 0.2) +
  labs(title = "Identifiants TLG et genres littéraires (plus de dix auteurs)", y = "genre")

Désormais, le graphique est bien plus lisible : on observe des ajouts “par grappe”, en particulier pour les “Comici”, “Tragici”, “Elegiaci”, et également pour les “Geographi”, “Lyrici/-ae”, “Medici”, “Oratores”, “Poetae”, “Rhetorici”, …

Jetons également un œil aux genres mis de côté, à savoir ceux qui contiennent dix auteurs ou moins.

tlg_authors_df %>%
  filter(code < 5000) %>%
  group_by(genre) %>%
  mutate(genre_n = n()) %>%
  ungroup() %>%
  filter(genre_n <= 10) %>%
  ggplot(aes(x = code, y = fct_reorder(genre, desc(genre)))) +
  geom_jitter(alpha = 0.3, shape = 16, width = 0, height = 0.1) +
  labs(title = "Identifiants TLG et genres littéraires (dix auteurs et moins)", y = "genre")

On observe des petits regroupements, qui ne sont pas systématiques : des “Paradoxographi” surtout, des “Bucolici” également, des “Doxographi”, peut-être aussi des “Mythographi”…

Essayons désormais des analyses en trois dimensions, en couleurs.

length(unique(tlg_authors_df$genre))
[1] 53

On trouve 52 genres (53, auquel on retire le genre “NA”) dans le fichier des auteurs TLG, qu’il est difficile de représenter clairement en couleurs. Nous gardons huit genres parmi les plus représentés. Ceci est une démarche exploratoire : l’idéal serait évidemment de produire plusieurs graphiques ; rappelons en outre, comme il est expliqué plus haut, que lorsque plusieurs genres s’appliquent à un auteur, nous avons gardé le premier apparaissant par ordre alphabétique.

count_tlg_genre <-
  tlg_authors_df %>%
  count(genre, sort = TRUE)
knit_print(count_tlg_genre[1:11,])

De cette liste, nous avons éliminé les “Historici/-ae” trop dispersés apportant de la confusion dans la lecture, et les “Scriptores Ecclesiastici”, assez dispersés également, même s’ils n’apparaissent que tardivement.

# On applique 8 genres avec une sélection de couleurs
tlg_authors_df %>%
  filter(genre %in% c(
    "Philosophici/-ae", "Comici", "Tragici", "Grammatici",
    "Epici/-ae", "Lyrici/-ae", "Rhetorici", "Medici"
  )) %>%
  ggplot(aes(x = code, y = date, color = genre)) +
  geom_point() +
  xlim(0, 2800) +
  ylim(-350, 600) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, dates et genres littéraires")

De ce premier graphique, il apparaît que les philosophes sont dispersés, mais restent en dehors de la zone des comiques et des tragiques. Nous observons aussi un longue ligne verticale représentant les médecins. Cette observation est plus parlante si nous ne gardons plus que ces quatre derniers genres.

tlg_authors_df %>%
  filter(genre %in% c(
    "Philosophici/-ae", "Comici", "Tragici", "Medici"
  )) %>%
  ggplot(aes(x = code, y = date, color = genre)) +
  geom_point() +
  xlim(0, 2800) +
  ylim(-350, 600) +
  scale_color_manual(values = couleurs[c(1, 6, 15, 25)]) +
  labs(title = "Identifiants TLG, dates et quatre genres")

Il est curieux de constater que la comédie semble encadrée par la tragédie.

# Zoom sur les identifiants des comiques, médecins et tragiques.
tlg_authors_df %>%
  filter(genre %in% c("Comici", "Tragici", "Medici")) %>%
  ggplot(aes(x = code, y = date, color = genre)) +
  geom_point() +
  xlim(0, 2000) +
  ylim(-350, 600) +
  scale_color_manual(values = couleurs[c(1, 6, 25)]) +
  labs(title = "Identifiants TLG, dates et trois genres")

En fait, on observe que les comiques regroupés de la sorte correspondent à la séquence que nous avions relevé, entre ~390 et ~520, dans notre première analyse (voir la section “Les identifiants par les noms”).

tlg_authors_df %>%
  filter(genre %in% c("Comici", "Tragici", "Medici")) %>%
  ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = genre)) +
  geom_point() +
  xlim(0, 1000) +
  scale_color_manual(values = couleurs[c(1, 6, 25)]) +
  labs(title = "Identifiants TLG, noms et trois genres", y = "name")

On voit clairement apparaître les comiques rangés par ordre alphabétique ! Si une ligne verticale apparaît avec les tragiques, entre ~260 et ~380, voire entre ~620 et ~750 pour les médecins, ces deux catégories paraissent néanmoins ne pas être rangées par ordre alphabétique.

Tentons une dernière série de graphiques, représentant les identifiants en fonction des noms, avec les genres en couleurs.

tmp_tlg_authors_genres <-
  tlg_authors_df %>%
  drop_na(genre) %>%
  count(genre) %>%
  arrange(desc(n)) %>%
  pull(genre)

tlg_authors_df %>%
  filter(genre %in% tmp_tlg_authors_genres[0:8]) %>%
  ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = genre)) +
  geom_point() +
  xlim(0, 5000) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, noms et genres littéraires (série 1)", y = "name") +
  theme(axis.text.y = element_blank())

tlg_authors_df %>%
  filter(genre %in% tmp_tlg_authors_genres[9:16]) %>%
  ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = genre)) +
  geom_point() +
  xlim(0, 5000) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, noms et genres littéraires (série 2)", y = "name") +
  theme(axis.text.y = element_blank())

tlg_authors_df %>%
  filter(genre %in% tmp_tlg_authors_genres[17:24]) %>%
  ggplot(aes(x = code, y = fct_reorder(name, desc(name)), color = genre)) +
  geom_point() +
  xlim(0, 5000) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, noms et genres littéraires (série 3)", y = "name") +
  theme(axis.text.y = element_blank())

remove(tmp_tlg_authors_genres)

Rien d’extrêmement clair ne se distingue, en sus de ce que nous avons remarqué auparavant, si ce n’est éventuellement un groupement de poètes lyriques autour de 250 (série 2), et de “Poetae” autour de 2600 (série 3), mais qui ne paraissent pas classés par ordre alphabétique.

Il faudrait regarder les choses plus en détail, et éventuellement modifier ou compléter nos données de départ : rappelons que pour un grand nombre d’auteurs, les genres, récupérés du CLTK, nous sont manquants. De même, les dates retenues pourraient être imprécises, ou les noms pourraient être différents de ceux retenus au moment de la classification – voire, pour être plus précis, les noms pourraient, sans être totalement différents, être indexés à une initiale distincte de la première lettre apparaissant dans le nom dont nous disposons.

2.5. Identifiants et lieux

Pour la classification PHI, l’essentiel paraît expliqué – il ne resterait qu’à déterminer plus précisément les frontières des périodes considérées, ainsi que les noms utilisés, et éventuellement, la raison des “trous” dans la numérotation.

Il ne nous reste plus qu’à essayer d’expliquer, pour la classification TLG, d’une part l’ordre des séquences, d’autre part certaines séquences particulières, dont pour certaines aucune logique claire n’est apparue jusque-là. Pour l’ordre des séquences entre elles, la logique paraît difficile à élucider par la confrontation des variables à notre disposition. Pour ce qui est des portions inexpliquées, intéressons-nous en particulier aux identifiants au-delà de 1800, qui ne suivaient vraisemblablement pas la logique alphabétique.

Tentons donc d’observer si les lieux pourraient jouer un rôle dans l’attribution des identifiants numérotés à partir de 1800.

tlg_authors_df %>%
  filter(code > 1800 & code < 5000) %>%
  drop_na(place) %>%
  ggplot(aes(x = code, y = fct_reorder(place, desc(place)), color = place)) +
  geom_point() +
  scale_color_manual(values = c(couleurs, "#000000", "#000000")) +
  labs(title = "Identifiants TLG et lieux (1800-5000)", y = "place")

Rien d’évident ne se dégage de ce premier graphique : un même lieu se répartit souvent tout au long de la numérotation. Essayons de croiser avec les dates pour distinguer des tendances.

Comme la colonne “place” contient 47 lieux différents, cela ne sera pas lisible si nous attribuons une couleur à chacun d’eux. Nous allons déterminer les lieux qui apparaissent le plus fréquemment, pour les codes 1800 et plus.

count_tlg_place <-
  tlg_authors_df %>%
  filter(code > 1800) %>%
  count(place, sort = TRUE)
knit_print(count_tlg_place[1:11,])

Comme nous l’avons fait pour les genres, nous gardons les 8 pays pour lesquels nous observons le plus d’occurrences (ici, au moins 7 occurrences, en choisissant arbitrairement Chypre plutôt que la Libye qui sont ex aequo).

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy",
    "Syria", "Israel", "Palestine", "Cyprus"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(1800, 5000) +
  ylim(-350, 1600) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, dates et lieux (1800-5000)")

On observe plusieurs lignes verticales représentant des auteurs de Turquie : l’une vers le code 2750, concerne des auteurs d’environ 1200 à environ 1400; l’autre dans les codes 3000 concerne des auteurs de 800 à 1500 ; il semble également y avoir des lignes concernant des auteurs d’Égypte. Comme il est difficile de lire ce graphique, nous éliminons les lieux pour lesquels nous constatons moins de 30 occurrences, et nous allons diviser les graphiques en tranches de codes, à partir des observations du tableau en deux dimensions “Identifiants TLG et noms (0-5000)”, figurant dans la section “Les identifiants par les noms”. On y voyait des concentrations de points qui ne formaient pas de lignes, pour les codes 1800 à 3000 et 4000 à 4400.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy", "Syria"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(1800, 3000) +
  ylim(-350, 1600) +
  scale_color_manual(values = couleurs[c(1, 7, 13, 19, 25)]) +
  labs(title = "Identifiants TLG, dates et 5 lieux (1800-3000)")

Il semblerait que plusieurs lignes se dessinent de manière éparse. De nouveaux zooms sont nécessaires.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy", "Syria"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(1800, 2100) +
  ylim(-350, 750) +
  scale_color_manual(values = couleurs[c(1, 7, 13, 19, 25)]) +
  labs(title = "Identifiants TLG, dates et 5 lieux (1800-2100)")

Quelques débuts de lignes apparaissent vers 1950, mais il est difficile d’établir une corrélation entre codes et lieux. La ligne rouge horizontale apparaissant est probablement davantage liée à la date qu’au lieu : lieux et périodes de production d’écrits grecs sont souvent liés.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy", "Syria"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(2100, 2300) +
  ylim(-350, 750) +
  scale_color_manual(values = couleurs[c(1, 7, 13, 19, 25)]) +
  labs(title = "Identifiants TLG, dates et 5 lieux (2100-2300)")

Nous constatons des agrégats de points de même couleur, mais il est difficile d’en tirer des conclusions, d’autant plus qu’il manque beaucoup de lieux dont les points de couleurs auraient apporté davantage de bruit.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy", "Syria"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(2700, 3300) +
  ylim(-350, 1600) +
  scale_color_manual(values = couleurs[c(1, 7, 13, 19, 25)]) +
  labs(title = "Identifiants TLG, dates et 5 lieux (2700-3300)")

Cette portion a pour caractéristique de concerner presque exclusivement la Turquie, du moins pour les zones retenues.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy",
    "Syria", "Israel", "Palestine", "Cyprus"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(2700, 3300) +
  ylim(-350, 1600) +
  scale_color_manual(values = couleurs[c(1, 4, 6, 9, 11, 15, 20, 25)]) +
  labs(title = "Identifiants TLG, dates et 8 lieux (2700-3300)")

Cela semble se confirmer lorsque nous élargissons cette observation aux huit pays les plus importants de la tranche 1800 et plus. Cependant, une recherche élargie à tous les lieux permettrait peut-être d’apporter une conclusion. Malheureusement, elle est impossible avec la pléthore des 52 couleurs, surtout que ggpplot les détermine selon l’ordre alphabétique et non selon la proximité géographique.

tlg_authors_df %>%
  filter(place %in% c(
    "Turkey", "Greece", "Egypt", "Italy", "Syria"
  )) %>%
  ggplot(aes(x = code, y = date, color = place)) +
  geom_point() +
  xlim(4000, 4400) +
  ylim(-350, 1600) +
  scale_color_manual(values = couleurs[c(1, 7, 13, 19, 25)]) +
  labs(title = "Identifiants TLG, dates et 5 lieux (4000-4400)")

Rien de significatif ne semble émerger de cette tranche.

Rien de très conclusif n’apparaît de cette recherche sur les lieux des auteurs en rapport avec le code TLG au delà de 1800.

Conclusion

Après cette exploration, nous pouvons conclure plusieurs choses – conclusions qui pourraient être précisées et enrichies à de nombreux égards.

Synthèse des résultats

Comme nous l’avions pressenti devant le caractère non-évident de la numérotation, nous avons établi que l’attribution des identifiants ne recouvre par une logique uniforme, mais obéit à une pluralités de facteurs. À cet égard, l’emploi d’analyses graphiques s’est révélé particulièrement fécond. Nous avons de plus pu établir l’existence de séquences spécifiques, possédant parfois chacune une logique propre.

Dans le cas du code PHI des textes latins du projet Perseus, un premier découpage est chronologique, le code étant proportionnel aux dates de chaque auteur, et le second, au sein de chaque période ainsi définie, est alphabétique. Le détail des dates retenues pour la classification, ainsi que du terme sur lequel se fonde la classification alphabétique, pourrait être affiné – du moins avons-nous établi que l’indexation alphabétique ne s’appuyait pas sur le praenomen. Ces deux logiques semblent recouvrir de manière homogène l’ensemble de la numérotation, les points aberrants appelant à être étudiés au cas par cas, par exemple pour vérifier le nom employé.

Les identifiants du Thesaurus Linguae Graecae, plus nombreux, suivent des règles davantage complexes. On y aperçoit plusieurs séquences, pour certaines desquelles nous sommes parvenus à restituer la logique. Nous avons ainsi discerné quatre séquences ordonnées par ordre alphabétique, dont l’une correspond aux auteurs comiques. D’autres regroupements se font également par genre littéraire, par exemple pour les auteurs tragiques ou les médecins, avec un classement interne ne suivant pas l’ordre alphabétique. D’autres partie de la numérotation nous sont en revanche restées obscures. Nos analyses exploratoires n’ont notamment pas permis de discerner de classification par lieu.

Pistes pour exploration ultérieure

Nous sommes ainsi parvenus à défricher le terrain et à établir certaines lignes de force guidant la numérotation des identifiants classiques considérés. Les explications au demeurant peuvent encore être précisées. Le présent travail pourrait ainsi aisément être complété, en partant des données mises au propres que nous avons établies, y adjoignant des variables ou en raffinant celles existantes, et en employant des méthodes d’analyse similaires, éventuellement éclairé par des saillies plus individuelles sur les tableaux et leurs éléments. De nombreuses pistes se sont en effet présentées à nous, sans qu’il nous ait été possible de tout à fait les explorer dans le temps qui nous était imparti.

Raffinement des variables existantes

Comme nous l’avons fait remarquer au cours de notre étude, plusieurs des variables que nous avons employé présentent des aspérités qu’il serait possible d’arrondir.

Pour ce qui est des noms, nous avons vu que le terme employé pour l’indexation alphabétique était d’importance : récupérer plus proprement les noms de références des auteurs latins aurait vraisemblablement permis d’affermir les résultats. Il en va de même pour les auteurs grecs : un problème similaire pourrait expliquer certains des points aberrants que l’on a pu retrouver dans les graphiques concernés.

Pour les dates, il aurait également été possible de mener des analyses complémentaires, en particulier pour clarifier précisément le découpage de la classification PHI, avec les données établies ou des données supplémentaires, pour déterminer exactement si le découpage se faisait en fonction de la date de naissance, la date de mort, ou d’une autre date qui pourrait par exemple correspondre à celle d’une œuvre particulière.

En ce qui concerne les genres, les données auraient pu être complétées : pour les auteurs grecs notamment, il aurait été possible de récupérer l’information directement depuis la variable “nom”, en sus des données du CLTK. Rappelons également que nous avons retenu arbitrairement un seul genre lorsqu’à un identifiant y correspondait plusieurs – il aurait été possible de dupliquer les lignes concernées pour faire apparaître l’identifiant à chaque endroit de ces genre multiples, et le cas échéant de déterminer à quel genre l’auteur était indexé pour déterminer son identifiant.

Pour les lieux, nous ne nous sommes penchés que sur ceux qui comportaient le plus d’occurrences pour les tranches d’identifiants étudiées. Nous aurions pu grouper les lieux par régions géographiques ou au contraire prendre en compte les villes lorsqu’elles étaient précisées et placer les identifiants en dégradés de couleurs sur une carte géographique. De même, nous rappelons que nous n’avons arbitrairement retenu qu’un seul lieu lorsque plusieurs figuraient pour un auteur unique.

Adjonction de variables connexes

Les caractéristiques sur lesquelles nous avons fondé nos analyses sont propres aux auteurs considérés – la date de mort par exemple est bien propre à l’auteur en tant que personne. Néanmoins, ce biais pourrait ne pas correspondre tout à fait à la construction des corpus étudiés : il semblerait qu’un identifiant soit parfois attribué à un sous-ensemble d’œuvres particulier, comme nous l’avons relevé pour les correspondances éspitolaires. Il se pourrait alors que les identifiants dépendent de traits propres à ces œuvres – par exemple, le nombre d’œuvres associées à cet identifiant, ou leur longueur. La constitution d’une base de données connexes comprenant les œuvres répertoriées pourrait à cet égard se montrer utile.

Un autre trait fondamental pour un classiciste, pouvant alors entrer en ligne de compte, serait celui de la canonicité. En effet, certains auteurs considérés comme canons apparaissent dans la tradition comme plus importants que d’autres. Les équipes ayant pris en charge la numérisation des œuvres du TLG et du catalogue Perseus ont pu ainsi procéder en priorité à l’inventaire des auteurs jugés les plus importants, apparaissant alors vraisemblablement au début de la classification. Si cette dimension n’est pas aisément formalisable ou quantifiable, elle est à considérer, et un œil connaisseur de la tradition pourrait la discerner sur les premières centaines d’identifiants du TLG notamment – les corpus canons étant souvent ceux les mieux conservés, fréquemment étudiés dans le cadre scolaire, à la postérité culturellement importante, plus souvent d’époque classique, ou compilant de précieux fragments d’œuvres perdues.

Croisant ces deux dimensions, la question de manuscrits pourrait également importer. En effet, tous les ouvrages numérisés dans le TLG ou Perseus naissent d’une tradition, directe ou indirecte. Pour une même œuvre, il peut donc y avoir plusieurs manuscrits. Peut-être ces manuscrits similaires mais différents ont-ils donné lieu à des schémas d’attributions d’identifiants spécifiques, ou peut-être certains pans de la numérotation dépendent de cette logique propre aux sources, pouvant par exemple regrouper des textes provenant d’un même recueil de fragments, d’autant plus pour les corpus vraisemblablement très lacunaires désignés par certains identifiants. La prise en compte de la taille de chaque corpus pourrait alors à cet égard être éclairante.

Méthodologies complémentaires

Pistes ethnographiques

Ces dernières remarques nous renvoient à l’histoire de la constitution des corpus, et plus spécifiquement des bases de données que sont le TLG et Perseus. Ces plateformes ont connu différentes phases de développement, vraisemblablement soumis au gré des financements, des campagnes de numérisation, des priorités du moment, ce qui influence certainement la numérotation des auteurs, et pourrait en particulier expliquer les différentes séquences que nous avons aperçues pour le TLG. Tous les auteurs, toutes les œuvres n’ont pas été numérisées en une seule fois. Le TLG en donne d’ailleurs un aperçu sur la page d’accueil de son site internet de l’évolution des documents numérisés. Les ajouts successifs sont très réguliers, appellant à chaque fois attribution d’une nouvel identifiant.

Des matériaux ethnographiques, comme des archives et des témoignages, plus proche de méthodes classiques d’investigation historique, apporteraient à cet endroit des éclairages utiles quant à l’histoire de la constitution de ces classifications. À cet égard, certaines sources bibliographiques pourraient vraisemblablement compléter l’analyse. On pourrait notamment se référer à Berkowitz Luci, “Ancilla to the Thesaurus Linguae Graecae : The TLG Canon” (in Jon Solomon (éd.), Accessing Antiquity. The Computerization of Classical Studies (p. 34-61), University of Arizona Press, Tucson, 1993), chapitre d’ouvrage donnant des précisions intéressantes quant au rôle qu’a joué l’American Philological Association, un de ses comités ayant sélectionné les textes à inclure dans le Thesaurus Linguae Graecae.

Pistes informatiques

En restant dans l’analyse numérique, il existe également des pistes et méthodes que nous n’avons pas explorées.

Notamment, les identifiants pourraient être par endroit être composés de plusieurs facteurs, justapoxé pour donner le nombre qui sert d’identifiant. Par exemple, les deux premiers chiffres pourraient correspondre à une variable, et les deux suivants à une autre – ces deux chiffres seraient ensuite adjoints pour donner un identifiant à quatre chiffres. Cette hypothèse, encore à explorer, pourrait contribuer à expliquer les sauts de numérotation, voire les séquences jusque là incomprises.

Nous nous sommes de plus limités, sur le plan de l’analyse statistique, principalement à des graphiques en deux ou trois dimensions. Il aurait par exemple été possible, pour faire apparaître sur une seule image une multiplicité de variables et n’en rien rater, de réalisation par exemple des analyses par correspondances multiples (ACP).

Annexes

Explorations subsidiaires

Nous consignons ici quelques analyses supplémentaires, non peaufinées et non intégrées à notre démonstration. Nous ne les commenterons pas mais les laissons à la curiosité du lecteur.

Récupération des hononymes

#' Get hononyms.
#' @param df Dataframe of authors.
#' @return Dataframe of authors who have hononyms.
get_homonyms_df <- function(df) {
  res_df <-
    df %>%
    count(name, name = "name_n") %>%
    filter(name_n > 1) %>%
    inner_join(df, by = "name") %>%
    relocate(name, name_n, .after = init)
  return(res_df)
}
get_homonyms_df(tlg_authors_df)
# We can observe 217 hononyms in `tlg_authors_df`.
# Aeschylus (5th BCE) appears both with code 85 and 885.
# Xenophon (4th BCE) appears both with code 32 and 1754.
get_homonyms_df(phi_authors_df)
# We can observe 12 honomnyms in `phi_authors_df` (those last are only n/a).

Explorations subsidiaires des données

tlg_authors_df %>% filter(str_detect(name, "(?i)epistul"))
tlg_authors_df %>% filter(str_detect(name, "(?i)anonym"))
tlg_authors_df %>% filter(str_detect(name, "(?i)paradox"))

Analyse de correspondances principales

pacman::p_load(FactoMineR, dummy)

# TODO: Code `init` into one numeric variable, from 1 to 26.

#' Format an authors dataframe
#' so it can be send to the `PCA()` function.
#' @param df Dataframe to format.
#' @param genre Boolean indicating if "genre" is present in the df.
format_to_pca_df <- function(df, genre = TRUE) {
  res_df <-
    df %>%
    # Drop useless variables and NA
    select(-name, -date_active, -date_active_str, -date_begin_str, -date_end_str) %>%
    drop_na() %>%
    # Dichotomize qualitative variables,
    # to transform them into quantitative ones.
    # It is inspired by the method used in logistic regression.
    mutate(dummy(tibble(place))) %>%
    mutate(dummy(tibble(init))) %>%
    select(-init, -place)
  if (genre) {
    res_df <- res_df %>% 
      mutate(dummy(tibble(genre))) %>%
      select(-genre)
  }
  res_df <- res_df %>%
    mutate_all(as.numeric)
  return(res_df)
}

phi_pca_df <- format_to_pca_df(phi_authors_df, genre = FALSE)
phi_pca <- PCA(phi_pca_df)

tlg_pca_df <- format_to_pca_df(tlg_authors_df)
tlg_pca <- PCA(tlg_pca_df)

# A correlation between `code` and `date` seems to appear.
# Those are the variables that differenciate the most individuals.
# Initials seem to have no correlation with those two,
# and to characterize the most the second dimension.

Code de démonstration

Sélection dans un tableau

tmp <-
  tlg_authors_df %>%
  # Select columns
  select(name, code, date_active) %>%
  # Drop missing values
  drop_na(date_active)

Notice de spécifications techniques, pour expliciter l’environnement de développement utilisé

#' A list of loaded packages, with their respective versions.
#' @return str
packages_str <- function() {
  packages <- pacman::p_loaded() %>% sort()
  package_str_v <- packages %>%
    map(~ paste0("- ",.," v",pacman::p_version(.)))
  str <- paste(package_str_v, collapse = "\n")
  return(str)
}

#' A technical notice
#' @details Display:
#'   - exact date of document generation
#'   - OS used
#'   - R version used
#'   - Packages loaded with their version  
#' Use in the text body of the `.rmd` document
#' with `r technical_notice_str()`.
#' @return str
technical_notice_str <- function() {
  return(paste0(
"Le présent document a été généré le ",format(Sys.time(), "%d %b %Y à %X")," sous ",str_to_title(.Platform$OS.type)," avec les ressources suivantes :

- ",R.version.string,"

*Bibliothèques externes*

",packages_str()
  ))
}

Module d’exportation

write_csv(phi_authors_df, here("projet_final/output/phi_authors_df.csv"))
write_csv(tlg_authors_df, here("projet_final/output/tlg_authors_df.csv"))

Références

Ressources externes

  • Perseus Project, “Authors-Abbreviation-Editions”, Tableur en ligne (lien).

  • Classical Langage ToolKit, “Author-Epithet”, Fichier .json (lien).

  • Internet et ses innombrables ressources pour apprendre et répondre aux problèmes techniques rencontrés.

Environnement de développement

Le présent document a été généré le 12 déc. 2021 à 15:06:05 sous Windows avec les ressources suivantes :

  • R version 4.0.3 (2020-10-10)

Bibliothèques externes

  • dplyr v1.0.7
  • dummy v0.1.3
  • FactoMineR v2.4
  • forcats v0.5.1
  • ggplot2 v3.3.3
  • here v1.0.1
  • jsonlite v1.7.2
  • knitr v1.31
  • purrr v0.3.4
  • readr v2.1.0
  • skimr v2.1.2
  • stringr v1.4.0
  • tibble v3.1.6
  • tidyr v1.1.4
  • tidyverse v1.3.1

Historique des versions

v1.4-tristan.1

  • Corrections et ajustements divers
    • Corrections dans les formulations
    • Réécritures partielles notamment dans l’introduction et la conclusion
    • Considérations de mise en page
    • Expliciation du code de la notice technique
    • Remplacement de colour par color pour homogénéiser l’orthographe, en faveur de la plus courte
  • Ajouts divers
    • Explicitation supplémentaire quant au principe d’un tableau de données
    • Création d’une section “Analyse subsidiaire” et intégration d’une tentative d’ACP
    • Ajout de tests de corrélation (identifiant et date, cor.test())
    • Ajout d’une fonction pour ajuster l’affichage des vecteurs (print_vector())

v1.3 (2021-02-09T18:30)

  • Fusion des versions v1.3-florence, v1.3-nadine.2 et v1.3-tristan.

v1.3-tristan (2021-02-09T18:20)

  • Ajout de fonctions d’exploration (section “Code de démonstration”)

v1.3-nadine.2 (2021-02-09T12:51)

  • Correction de liens internes

v1.3-nadine.1 (2021-02-07T14:40)

  • Précisions sur les lieux et les noms d’auteurs dans “1. Formatage des données > Variables recherchées”
  • Correction de deux graphiques oubliés (ordre alphabétique)
  • Ajout d’un petit paragraphe sur les lieux dans “Conclusions > Les limites de notre méthode”

v1.3-florence (2021-02-08T12:33)

  • Ajouts de précision à la suite des commentaires d’Aurélien Berra
  • Relecture orthographique et grammaticale

v1.2 (2021-02-06T17:40)

  • Fusion des versions v1.2-nadine.4 et v1.2-tristan, qui consistent en un début de prise en compte des commentaires d’Aurélien Berra

v1.2-tristan (2021-02-06T15:20)

  • Analyses complémentaires
    • Ajout de deux graphiques quant aux premières analyses sur les genres
    • Ajout d’analyses par modèles linéaires pour préciser la corrélation entre identifiants et dates chez les latins
  • Changements mineurs
    • Clarification de la mesure des valeurs manquantes (na_p renommée na_rate et arrondie)
    • Précision sur la liste des équivalents à des valeurs manquantes
    • Précision sur les balises BCE/CE comme facteur commun
    • Correction manuelle pour TLG#0237 (Anacréon)
    • Corrections mineures

v1.2-nadine.4 (2021-02-06T17:13)

  • Corrections et suppression de certains commentaires sur les genres

v1.2-nadine.3 (2021-02-06T01:39)

  • Commentaires et corrections

v1.2-nadine.2 (2021-02-05T17:00)

  • Réintégration des modifications de la v1.1 (la v1.0 avait été prise comme origine de la v1.2-nadine.1)

v1.2-nadine.1 (2021-02-04T22:43)

  • Mise en ordre alphabétique dans le sens de la lecture (bas en haut) sur les graphiques, et corrections des interprétations en ce sens

v1.1 (2021-01-11T13:00)

  • Précisions et corrections dans l’introduction et la conclusion
  • Rendu en carnet (notebook), avec table des matières flottante

v1.0 (2021-01-11T01:29)

  • Intégration de l’introduction et de la conclusion
  • Dernières vérifications des commentaires
  • Vérifications typographiques

v0.14 (2021-01-10T22:50)

  • Ajout d’un emplacement pour la section “conclusion”
  • Suppression des éléments inutiles
  • Précisions à la fin de la section “démarche”
  • Précisions à la fin de la section “identifiants, dates et initiales” pour les latins
  • Précisions et ajouts au début et à la fin de la section “genres”
  • Précisions au début de la section “lieux”
  • Améliorations mineures

v0.13 (2021-01-10T14:00)

  • Corrections orthographiques
  • Ajout d’une analyse par lieux

v0.12 (2021-01-09T22:50)

v0.11 (2021-01-09T19:45)

  • Améliorations (pleins !)

v0.10 (2021-01-09T13:40)

  • Réintégration des versions intermédiaires de Nadine et Florence
Nom original Version correspondante
v0.5 (modifiée) / v0.6 v0.6
v0.5nad v0.7
v0.5Nad-7janv v0.8
v0.5Nad-8janv v0.9
  • Analyses graphiques
    • En deux dimensions : code et nom, code et date
    • En trois dimensions : code, date, genre
  • Nouveau tableau pour les latins en retirant les prénoms
  • Amélioration de la structure
  • Améliorations mineures par endroits
  • Rédaction partielle d’explications plus générales
  • Les balises “@!” indiquent que l’élément associé demande vérification voire suppression

v0.5 (2021-01-05T20:20)

  • Correction d’une erreur : les lignes n’étaient pas dégroupées après formatage des dates
  • Adjonction des genres
  • Déplacement de la colonne des codes au début pour clarté
  • Possibles autres changements mineurs

v0.4 (2021-01-05T16:40)

  • Formatage des lieux
  • Présentation convenable des variables conservées depuis le tableur Perseus
  • Corrections mineures diverses

v0.3 (2021-01-05T12:10)

  • Correction d’une erreur dans la récupération des codes (pour bien récupérer les auteurs dont le code est inférieur à 1000)
  • Utilisation de la moyenne plutôt que de la valeur de gauche, quand la date donnée est un intervalle (pour la transformer en nombre)
  • Changements anecdotiques
    • Ajout en annexes de codes de démonstration
    • Ajout en annexes d’un module d’exportation
    • Ajout en annexes de la liste des dépendances, générée dynamiquement
    • Ajout d’une section sur les possibles erreurs dans les dates des données récupérées
  • Changements mineurs
    • À l’intérieur de convert_dates(), renommage de is_before en is_bce
    • Suppression des valeurs manquantes pour la colonne code.
    • Corrections d’erreurs orthographiques dans la documentation

v0.2 (2020-12-31T15:40)

  • Complétion du formatage des dates
  • Ajout de remarques sur les dates et la bibliothèque lubridate
  • Correction d’erreurs ponctuelles dans les données

v0.1 (2020-12-31T12:50)

  • Structure générale du document
  • Configuration du fichier RMarkdown
  • Extraction de la liste des auteurs depuis le tableur du Projet Perseus
  • Début de formatage des dates
LS0tDQp0aXRsZTogIk5vbWVuY2xhdHVyZXMgZGVzIGNvcnB1cyBhbnRpcXVlcyINCmF1dGhvcjoNCiAgLSBIYW1hcmQsIFRyaXN0YW4NCiAgLSBMaWVuaGFyZCwgRmxvcmVuY2UNCiAgLSBSYWtvZnNreSwgTmFkaW5lDQpzdWJ0aXRsZTogVmVyc2lvbiAxLjMrIOKAkyAyMDIxLTAyLTA5DQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICczJw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBodG1sX25vdGVib29rOg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICczJw0KZWRpdG9yX29wdGlvbnM6DQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KPCEtLSBybWFya2Rvd246OnJlbmRlcigicHJvamV0X2ZpbmFsXFxhbmFseXNlX2lkZW50aWZpYW50c192MS40LXRyaXN0YW4uMS5ybWQiLCAiaHRtbF9ub3RlYm9vayIpIC0tPg0KDQoqKlByb2pldCBjb2xsZWN0aWYgZGUgZmluIGRlIHNlbWVzdHJlIHBvdXIgbGUgY291cnMgZCdBdXLDqWxpZW4gQmVycmEsICJIdW1hbml0w6lzIG51bcOpcmlxdWVzIDMiLCDDoCBsJ1VuaXZlcnNpdMOpIFBhcmlzIE5hbnRlcnJlLCBkw6ljZW1icmUgMjAyMMKg4oCTICpbUHVibGljYXRpb24gZW4gbGlnbmVdKGh0dHBzOi8vY2xhc3NudW0uaHlwb3RoZXNlcy5vcmcvNjAzNykuKioqDQoNCipTaSBBdXLDqWxpZW4gQmVycmEgbmUgZmFpdCBwYXMgZm9ybWVsbGVtZW50IHBhcnRpZSBkZSBsYSBsaXN0ZSBkZXMgYXV0ZXVycyBkdSBwcsOpc2VudCBkb2N1bWVudCwgY2UgdHJhdmFpbCBuJ2F1cmFpdCBwYXMgw6l0w6kgcG9zc2libGUgc2FucyBsdWnCoDogbm91cyBzb3VoYWl0b25zIGx1aSBhZHJlc3NlciB0b3VzIG5vcyByZW1lcmNpZW1lbnRzLCBub24gc2V1bGVtZW50IHBvdXIgc2VzIGNvdXJzIHF1aSBub3VzIG9udCBpbml0acOpcyBhdXggb3V0aWxzIGljaSBtYW5pcHVsw6lzLCBwb3VyIHNvbiDDqW5vbmPDqSBzdGltdWxhbnQgcG9zYW50IGxlIHByb2Jsw6htZSBhdXF1ZWwgbm91cyBub3VzIGNvbmZyb250b25zIGljaSwgbWFpcyBlbmNvcmUgcG91ciBzYSBkaXNwb25pYmlsaXTDqSBhaW5zaSBxdWUgc2VzIG5vbWJyZXVzZXMgcmVtYXJxdWVzLCByZXNzb3VyY2VzIGV0IGluZGljYXRpb25zLCBwcm9kaWd1w6llcyBhdSBjb3VycyBkZSBub3RyZSB0cmF2YWlsIGV0IHN1aXRlIMOgIHNlcyByZWxlY3R1cmVzIHRyw6hzIGF0dGVudGl2ZXMuIE5vdXMgYXZvbnMgdGVudMOpIGQnZW4gdGVuaXIgY29tcHRlIGV0IGQnaW50w6lncmVyIHNlcyBhcHBvcnRzIGF1dGFudCBxdWUgcG9zc2libGUsIHNpIGJpZW4gcXVlIGNlIHRyYXZhaWwgZXN0IGF1c3NpIHVuIHBldSBsZSBzaWVuLioNCg0KIyBBbmFseXNlIGRlIG5vbWVuY2xhdHVyZXMgZGVzIGNvcnB1cyBkZSBsaXR0w6lyYXR1cmUgYW50aXF1ZSAoVExHIGV0IFBISSkNCg0KIyMgUHLDqXNlbnRhdGlvbg0KDQpMZSBkw6l2ZWxvcHBlbWVudCBkZXMgaHVtYW5pdMOpcyBudW3DqXJpcXVlcyBzJ2VzdCBhY2NvbXBhZ27DqSBkZSBsJ8OpbWVyZ2VuY2UgZGUgcGx1c2lldXJzIGlubm92YXRpb25zIHJlbm91dmVsYW50IGxlcyBwcmF0aXF1ZXMgZGVzIGNoZXJjaGV1cnMgZW4gaHVtYW5pdMOpcyBjbGFzc2lxdWVzLiBMYSBjcsOpYXRpb24gZGUgKipiaWJsaW90aMOocXVlcyBpbnRlcmFjdGl2ZXMqKiBlbiBmYWl0IHBhcnRpZSwgw6AgbCdpbnN0YXIgZHUgWypUaGVzYXVydXMgTGluZ3VhZSBHcmFlY2FlKl0oaHR0cDovL3N0ZXBoYW51cy50bGcudWNpLmVkdS8pIChUTEcpIGV0IGRlIGxhIFsqQmlibGlvdGjDqHF1ZSBOdW3DqXJpcXVlIFBlcnNldXMqXShodHRwOi8vd3d3LnBlcnNldXMudHVmdHMuZWR1L2hvcHBlci8pLiBMZXMgc2l0ZXMgb2ZmcmFudCBsJ2FjY8OocyDDoCBjZXMgZGV1eCBiaWJsaW90aMOocXVlcyBkaXNwb3NlbnQgZCd1biBncmFuZCBub21icmUgZGUgZm9uY3Rpb25uYWxpdMOpcywgbW9iaWxpc2FibGVzIHN1ciB1biBjYW5vbiB0csOocyBsYXJnZSBkJ2F1dGV1cnMgZXQgZCfFk3V2cmVzwqDigJMgYWNjZXNzaWJsZXMgZ3JhdHVpdGVtZW50IHBvdXIgUGVyc2V1cywgZXQgc3VyIGFib25uZW1lbnQgcG91ciBsZSBUTEcuIEwnw6l0dWRlIGQnxZN1dnJlcyB5IGVzdCBhaW5zaSBncmFuZGVtZW50IGZhY2lsaXTDqSBwYXIgbGEgbWlzZSDDoCBkaXNwb3NpdGlvbiBkZSBwbHVzaWV1cnMgZGljdGlvbm5haXJlcywgZGUgcHJvcG9zaXRpb25zIGQnYW5hbHlzZSBncmFtbWF0aWNhbGUsIGRlIG1pc2VzIGVuIHBhcmFsbMOobGUgZW50cmUgbGVzIMWTdXZyZXMgc8OpbGVjdGlvbm7DqWVzLCBldCBtw6ptZSBkJ2FuYWx5c2VzIHN0YXRpc3RpcXVlcy4NCg0KQ2VsdWkgcXVpIGEgZMOpasOgIHBhcmNvdXJ1IGxlcyByYXlvbnMgdmlydHVlbHMgZGUgY2VzIGJpYmxpb3Row6hxdWVzwqDigJMgZXQgcGx1cyBlbmNvcmUgY2VsdWkgcXVpIGF1cmEgdGVudMOpIGQnZXhwbG9pdGVyIGluZm9ybWF0aXF1ZW1lbnQgY2VzIGRvbm7DqWVzwqDigJMgYXVyYSBwZXV0LcOqdHJlIHJlbGV2w6kgcXVlIGNoYXF1ZSBhdXRldXIsIGV0IGNoYXF1ZSDFk3V2cmUsIHkgcG9zc8OoZGUgdW4gKippZGVudGlmaWFudCB1bmlxdWUqKi4gVG91dGUgYmFzZSBkZSBkb25uw6llcyBpbmZvcm1hdGlxdWUgYXBwZWxsZSBlZmZlY3RpdmVtZW50IMOgIGRvdGVyIGNoYXF1ZSDDqWzDqW1lbnQgcXVpIGxhIGNvbXBvc2VudCBkJ3VuIGlkZW50aWZpYW50IHBvdXIgZW4gcGVybWV0dHJlIHVuZSBtYW5pcHVsYXRpb24gYWlzw6llwqDigJMgbCdpZGVudGlmaWFudCwgZ8OpbsOpcmFsZW1lbnQgc3VpdGUgZGUgbm9tYnJlcywgY29uZsOocmUgZW4gZWZmZXQgw6AgbCfDqWzDqW1lbnQgcXUnaWwgZMOpc2lnbmUgdW5lIHN0YWJpbGl0w6kgcXVpIGVuIGZhY2lsaXRlIGwnYWNjw6hzwqA6IHF1YW5kIGJpZW4gbcOqbWUgbGUgY29udGVudSBvdSBsZSB0aXRyZSBkZSBjZXQgw6lsw6ltZW50IGNoYW5nZXJhaXQsIGwnaWRlbnRpZmlhbnQsIGx1aSwgZGVtZXVyZS4NCg0KRGV1eCBjbGFzc2lmaWNhdGlvbnMgc2VydmVudCBkZSByw6lmw6lyZW5jZSBmcsOpcXVlbnRlIHBvdXIgZMOpc2lnbmVyIGxlcyDFk3V2cmVzIGNsYXNzaXF1ZXMgZXQgbGV1cnMgYXV0ZXVyc8KgOiBpbCBzJ2FnaXQgZGVzIGlkZW50aWZpYW50cyBhdHRyaWJ1w6lzIHBhciBsZSAqKlRMRyoqLCBwb3VyIGxlcyB0ZXh0ZXMgZ3JlY3MsIGV0IHBhciBsZSAqUGFja2FyZCBIdW1hbml0aWVzIEluc3RpdHV0ZSogKCoqUEhJKiopIHBvdXIgbGVzIHRleHRlcyBsYXRpbnMuIERhbnMgbGVzIGRldXggY2FzLCBsJ2lkZW50aWZpYW50IGVzdCBudW3DqXJpcXVlIGV0IGVzdCBjb21wb3PDqSBkZSBxdWF0cmUgY2hpZmZyZXPCoDogSG9tw6hyZSwgcGFyIGV4ZW1wbGUsIGVzdCBhc3NpZ27DqSDDoCBsJ2lkZW50aWZpYW50IGAwMDEyYCBkYW5zIGxlIFRMRy4gTCdpZGVudGlmaWFudCBkJ3VuZSDFk3V2cmUgZXN0IGFsb3JzIGNvbXBvc8OpIGRlIGwnaWRlbnRpZmlhbnQgZGUgc29uIGF1dGV1ciBzdWl2aSBkJ3VuIHBvaW50IHB1aXMgZGUgcGx1c2lldXJzIGF1dHJlcyBjaGlmZnJlcyBwb3VyIGNhcmFjdMOpcmlzZXIgbCfFk3V2cmUgZW4gcXVlc3Rpb24uDQoNClBvdXIgYXV0YW50LCBsYSBkb2N1bWVudGF0aW9uIHBvcnRhbnQgc3VyIGxhIGNvbnN0aXR1dGlvbiBkZSBjZXMgaWRlbnRpZmlhbnRzIGVzdCBsYWN1bmFpcmUsIGV0IHVuIHJhcGlkZSBjb3VwIGQnxZNpbCBhdXggaWRlbnRpZmlhbnRzIGR1IFRMRyBuZSBwZXJtZXQgcGFzIGQnZW4gZGlzY2VybmVyIGxhIGxvZ2lxdWUgZCdhdHRyaWJ1dGlvbsKgOiBsYSBudW3DqXJvdGF0aW9uIG5lICDDoCBwcmVtacOocmUgdnVlIMOqdHJlIG5pIGFscGhhYsOpdGlxdWUsIG5pIGNocm5vbG9naXF1ZSwgb3UgZW4gdG91dCBjYXMgcGFzIGRlIG1hbmnDqHJlIHVuaXZvcXVlLCBldCBvbiByZW1hcnF1ZSBxdWUgbGVzIGlkZW50aWZpYW50cyBzb250IGRpc2NvbnRpbnVzLCBjZXJ0YWlucyBtYW5xdWFudHMgZW50cmUgZGV1eCB2YWxldXJzwqA6IG9uIGEgYmllbiBIw6lzaW9kZSBjb3JyZXNwb25kYW50IGF1IGAwMDIwYCBldCBOaWNhbmRyZSBhdSBgMDAyMmAsIG1haXMgZW4gcmV2YW5jaGUgYXVjdW4gYXV0ZXVyIGF1IG51bcOpcm8gMjEuICoqT24gcydpbnRlcnJvZ2UgYWxvcnMgc3VyIGxhIGxvZ2lxdWUgaW50ZXJuZSBkZSBjZXMgaWRlbnRpZmlhbnRzKirCoOKAkyDDoCBtb2lucyBxdSdpbHMgbmUgc29pZW50IHF1J2FyYml0cmFpcmVzLi4uDQoNCk5vdXMgbm91cyBwcm9wb3NvbnMgZG9uYyBkZSBtZW5lciBsJ2VucXXDqnRlLiBBdSBkw6lwYXJ0IGluZm9ybWF0aXF1ZSwgY2V0dGUgZW5xdcOqdGUgZXN0IGF1c3NpIGhpc3RvcmlxdWXCoDogw6lsdWNpZGVyIGxhIG91IGxlcyBsb2dpcXVlcyBhdXhxdWVsbGVzIGNlcyBpZGVudGlmaWFudHMgcG91cnJhaWVudCBvYsOpaXIsIGMnZXN0IGF1c3NpIGluZm9ybWVyIGxlcyBjaG9peCBxdWkgb250IMOpdMOpIGZhaXRzIGxvcnMgZGUgbGEgY29uc3RpdHV0aW9uIGRlIGNlcyBiYXNlcyBkZSBkb25uw6llcy4gVW5lICoqYW5hbHlzZSBpbmZvcm1hdGlzw6llKiosIHBhcmHDrnQgcGFydGljdWxpw6hyZW1lbnQgaW5kaXF1w6llIHBvdXIgdGVudGVyIGRlIHLDqXNvdWRyZSBsJ8OpbmlnbWUgcXVpIHNlIHByw6lzZW50ZSDDoCBub3VzLCBsZXMgaWRlbnRpZmlhbnRzIGVuIHF1ZXN0aW9uIMOpdGFudCBudW3DqXJpcXVlcyBldCBzZSBjb21wdGFudCBwYXIgY2VudGFpbmVzIHBvdXIgbGEgY29kaWZpY2F0aW9uIGR1IFBISSwgcGFyIG1pbGxpZXJzIHBvdXIgY2VsbGUgZHUgVExHLiBMZXMgZG9ubsOpZXMgw6Agw6l0dWRpZXIgcHLDqXNlbnRlbnQgbCdhdmFudGFnZSBkJ8OqdHJlIGFpc8OpbWVudCBhY2Nlc3NpYmxlc8Kg4oCTIGRhdmFudGFnZSBxdWUgZGVzIG1hdMOpcmlhdXggZCdhcmNoaXZlcyBvdSBsZSByZWN1ZWlsIGRlIHTDqW1vaWduYWdlc8Kg4oCTIGV0IG5vdXMgdGVudGVyb25zIGRlIGNyb2lzZXIgbGVzIGlkZW50aWZpYW50cyBub24gc2V1bGVtZW50IGF2ZWMgbGVzIG5vbXMgZGVzIGF1dGV1cnMgY29uY2VybsOpcywgbWFpcyBhdXNzaSBhdmVjIGxldXJzIGRhdGVzLCBsZSBvdSBsZXMgZ2VucmVzIGxpdHTDqXJhaXJlcyBhdXhxdWVscyBpbHMgc2UgcmF0dGFjaGVudCwgYWluc2kgcXVlIGxldXIgbGlldSBkJ2V4ZXJjaWNlLg0KDQpBaW5zaSBjZXR0ZSDDqXR1ZGUsIHF1ZSBub3VzIGNvbmR1aXNvbnMgYXZlYyBsZSBbbGFuZ2FnZSBSXShodHRwczovL3d3dy5yLXByb2plY3Qub3JnLyksIGxhbmdhZ2UgW2xpYnJlXShodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzL29sZC1saWNlbnNlcy9ncGwtMi4wLmh0bWwpIGQnYW5hbHlzZSBkZSBkb25uw6llcywgYXBwb3J0ZSBhdSBwcmF0aWNpZW4gZGVzIGh1bWFuaXTDqXMgbnVtw6lyaXF1ZXMgw6AgbCdlc3ByaXQgY3VyaWV1eCwgZXQgw6AgbGEgY29ubmFpc3NhbmNlIGhpc3RvcmlxdWUsIHVuIMOpY2xhaXJhZ2UgdXRpbGUgZXQgdW5lIG3DqXRob2RlIG9yaWdpbmFsZS4gTm91cyBwcm9jw6lkZXJvbnMgdG91dCBkJ2Fib3JkIMOgIHVuZSBtaXNlIGVuIGZvcm1lIHN5c3TDqW1hdGlxdWUgZGVzIGRvbm7DqWVzIHF1ZSBub3VzIHNvbW1lcyBwYXJ2ZW51cyDDoCByw6ljdXDDqXJlciwgcG91ciBwb3V2b2lyIGRhbnMgdW5lIHNlY29uZGUgcGFydGllIGxlcyBzb3VtZXR0cmUgw6AgYW5hbHlzZXMgZ3JhcGhpcXVlcywgZCdvw7kgbm91cyB0aXJlcm9ucyBwbHVzaWV1cnMgcsOpc3VsdGF0cyBzeW50aMOpdGlzw6lzIGVuIGNvbmNsdXNpb24uDQoNCk5vdGV6IGF1IHBhc3NhZ2UgcXVlIG5vdHJlIMOpdHVkZSBzZSBjb25jZW50cmUgc3VyIGxlcyBpZGVudGlmaWFudHMgZGVzIGF1dGV1cnMsIGxhaXNzYW50IGRlIGPDtHTDqSBsYSBsb2dpcXVlIGRlIG51bcOpcm90YXRpb24gZGVzIMWTdXZyZXPCoDogw6AgcHJlbWnDqHJlIHZ1ZSwgY2hhcXVlIGF1dGV1ciBhIHVuZSBudW3DqXJvdGF0aW9uIHByb3ByZSDDoCBzZXMgxZN1dnJlcyAoMDAxLCAwMDIuLi4pLCBiaWVuIHF1ZSBjZWxsZS1jaSBwb3VycmFpdCBzdWl2cmUgZGVzIGxvZ2lxdWVzIHRyYW5zdmVyc2FsZXMsIHBhciBleGVtcGxlIHVuZSBjbGFzc2lmaWNhdGlvbiBjaHJvbm9sb2dpcXVlIHBhciBkYXRlIGQnw6ljcml0dXJlLiBDJ2VzdCB0b3V0IGNlIHF1ZSBub3VzIGVuIGRpcm9ucywgY2FyIGlsIG5vdXMgcGFyYcOudCBwcmlvcml0YWlyZSBkYW5zIGNldHRlIGludmVzdGlnYXRpb24gZGUgY29tbWVuY2VyIHBhciBub3VzIGZvY2FsaXNlciBzdXIgbGVzIGF1dGV1cnPCoDsgYXByw6hzIHRvdXQsIGMnZXN0IGxldXIgaWRlbnRpZmlhbnQgZXN0IGxlIHByZW1pZXIgYXBwYXJhaXNzYW50IHN1ciB1bmUgxZN1dnJlICgwMDEyLjAwMSwgMDAxMi4wMDIuLi4pLiBBbmFseXNlciBwbHVzIGZpbmVtZW50IGxhIGxvZ2lxdWUgZGUgbnVtw6lyb3RhdGlvbiBkZXMgxZN1dnJlcyBhcHBlbGxlcmFpdCDDoCB1bmUgw6l0dWRlIHNww6ljaWZpcXVlIHF1aSBkZW1hbmRlcmFpdCBkZSBmb3JtYXRlciBkaWZmw6lyZW1tZW50IGxlcyBkb25uw6llcyDDoCBub3RyZSBkaXNwb3NpdGlvbsKgOiBjZWNpIHBvdXJyYWl0IGZhaXJlIGwnb2JqZXQgZCd1biB0cmF2YWlsIHVsdMOpcmlldXIuDQoNCiMjIETDqW1hcmNoZSBhZG9wdMOpZQ0KDQpBdmFudCBkZSBub3VzIGF0dGVsZXIgYXV4IGZvcm1hdGFnZXMgZXQgw6AgbCdleHBsb3JhdGlvbiBwcm9wcmVtZW50IGRpdHMsIHJldmVub25zIHVuIGluc3RhbnQgc3VyIHF1ZWxxdWVzIGdyYW5kcyBwcmluY2lwZXMgbcOpdGhvZG9sb2dpcXVlcyBxdWkgZ3VpZGVudCBub3RyZSBpbnZlc3RpZ2F0aW9uLiBOb3VzIGNoZXJjaG9ucyBpY2kgw6AgZXhwbGlxdWVyIHVuZSB2YXJpYWJsZSwgw6Agc2F2b2lyIHVuIGlkZW50aWZpYW50LCBwYXIgZCdhdXRyZXMgdmFyaWFibGVzIHBvdGVudGllbGxlcywgY29tbWUgbGUgbm9tLCBsYSBkYXRlLCBsZSBsaWV1IG91IGxlIGdlbnJlIGxpdHTDqXJhaXJlLg0KDQpSYXBwZWxvbnMsIHBvdXIgY2xhcmlmaWVyIGxlcyBmb25kZW1lbnRzIGRlIGxhIHRlcm1pbm9sb2dpZSBxdWUgbm91cyBlbXBsb3lvbnMsIHF1J3VuZSAiKip2YXJpYWJsZSoqIiBlc3QgdW5lIGNhcmFjdMOpcmlzdGlxdWUgZCd1biDDqWzDqW1lbnQgY29uc2lkw6lyw6kuIERhbnMgdW4gdGFibGVhdSwgbGVzICJ2YXJpYWJsZXMiIGNvcnJlc3BvbmRlbnQgZ8OpbsOpcmFsZW1lbnQgYXV4IGNvbG9ubmVzLCBldCBsZXMgw6lsw6ltZW50cyBjb25zaWTDqXLDqXMgYXV4IGxpZ25lcy4gT24gcGV1dCBhdXNzaSBwYXJsZXIsIHBvdXIgbGVzIGxpZ25lcywgZCcib2JzZXJ2YXRpb25zIiwgZCciZW50csOpZXMiIG91IGQnIioqaW5kaXZpZHVzKioiLiBQb3VyIGNoYXF1ZSBpbmRpdmlkdSwgY2hhcXVlIHZhcmlhYmxlIHByZW5kIHVuZSAqKnZhbGV1cioqIG91IHVuZSBtb2RhbGl0w6kgcGFydGljdWxpw6hyZSwgYydlc3QgbGUgImNvbnRlbnUiIGRlIGxhIHZhcmlhYmxlLiBMZXMgbW9kYWxpdMOpcyBzb250IGFpbnNpIGwnZW5zZW1ibGUgZGVzIHZhbGV1cnMgcXVlIHBldXZlbnQgcHJlbmRyZSB1bmUgdmFyaWFibGXCoOKAkyBwbHVzIHByw6ljaXPDqW1lbnQsIG9uIHBhcmxlIGRlICIqKm1vZGFsaXTDqSoqIiBsb3JzcXVlIGxlIG5vbWJyZSBkZSB2YWxldXJzIHBvc3NpYmxlcyBlc3QgZmluaS4gUGFyIGV4ZW1wbGUsIGwnaWRlbnRpZmlhbnQgZXN0IHVuZSB2YXJpYWJsZSBxdWkgYSB1bmUgZm9ybWUgcGFydGljdWxpw6hyZSwgw6Agc2F2b2lyIHVuIG51bcOpcm8gZGUgMSDDoCA0IGNoaWZmcmVzLCBldCBwb3VyIGwnaW5kaXZpZHUgZMOpbm9tbcOpICJQbGF0b24iLCBsYSB2YXJpYWJsZSAiaWRlbnRpZmlhbnQiIHByZW5kIGxhIHZhbGV1ciAiMDA1OSLCoOKAkyBsYSB2YXJpYWJsZSAiZ2VucmUgbGl0dMOpcmFpcmUiIHF1YW50IMOgIGVsbGUsIGRvbnQgbGEgbGlzdGUgZGVzIG1vZGFsaXTDqXMgZXN0IGTDqWZpbmllIMOgIGwnYXZhbmNlLCBwcmVuZCBwb3VyICJQbGF0b24iIGxhIG1vZGFsaXTDqSAicGhpbG9zb3BoaWUiLg0KDQpTY2jDqW1hdGlxdWVtZW50LCB0b3V0IGNlY2kgc2UgcHLDqXNlbnRlIHNvdXMgY2V0dGUgZm9ybWXCoDoNCg0KLiB8ICoqVmFyaWFibGUgMSoqIHwgKipWYXJpYWJsZSAyKiogfCAuLi4NCiAtLS0gfCAtLS0gfCAtLS0gfCAtLS0NCiAqKkluZGl2aWR1IDEqKiB8IFZhbGV1ciAxIHwgTW9kYWxpdMOpIEEgfA0KICoqSW5kaXZpZHUgMioqIHwgVmFsZXVyIDIgfCBNb2RhbGl0w6kgQSB8DQogKipJbmRpdmlkdSAzKiogfCBWYWxldXIgMyB8IE1vZGFsaXTDqSBCIHwNCiAqKi4uLioqIHwgfCB8DQoNClBvdXIgb2JzZXJ2ZXIgY2UgcXVlIG5vdXMgb2J0ZW5vbnMgZGFucyBub3RyZSBjYXMsIGxlIGxlY3RldXIgcGV1dCBzZSByw6lmw6lyZXIgw6AgbGEgc2VjdGlvbiBbIkRvbm7DqWVzIGZpbmFsZXMiXSgjZG9ubsOpZXMtZmluYWxlcy1vYnRlbnVlcykuDQoNCkNvbnNpZMOpcm9ucyB1biBpbnN0YW50IGxlcyB0eXBlcyBkZXMgdmFyaWFibGVzIHF1aSBzb250IGVuIGpldSwgYXZhbnQgZGUgcHLDqXNlbnRlciBsZXMgw6l0YXBlcyBxdWkgdm9udCBub3VzIMOqdHJlIG7DqWNlc3NhaXJlcyBkYW5zIG5vdHJlIMOpdHVkZS4NCg0KIyMjIFR5cGVzIGRlIHZhcmlhYmxlcw0KDQpQb3VyIHkgdm9pciBwbHVzIGNsYWlyLCBkaXN0aW5ndW9ucyBsYSAibmF0dXJlIiBkZXMgdmFyaWFibGVzIHF1aSBzb250IGVuIGpldS4gT24gcGV1dCBkaWZmw6lyZW5jaWVywqA6DQoNCi0gTGVzIHZhcmlhYmxlcyAiKipjb250aW51ZXMqKiLCoDogaWwgcydhZ2l0IGRlIHZhcmlhYmxlcyBudW3DqXJpcXVlcywgc3VyIGxlc3F1ZWxsZXMgb24gcGV1dCBlZmZlY3R1ZXIgZGVzIG9ww6lyYXRpb25zIG1hdGjDqW1hdGlxdWVzIChjYWxjdWwgZGUgbW95ZW5uZSwgbWluaW11bSwgbWF4aW11bS4uLikuIElsIHMnYWdpdCBwYXIgZXhlbXBsZSBkZXMgaWRlbnRpZmlhbnRzIHNvdXMgbGEgZm9ybWUgZGUgbnVtw6lyb3Mgb3UgZGUgZGF0ZXMuIChOb3RvbnMgYXUgcGFzc2FnZSBxdWUgbGVzIGNhdMOpZ29yaWVzIHF1ZSBub3VzIHByb3Bvc29ucyBuZSBjb3JyZXNwb25kZW50IHBhcyBzY3J1cHVsZXVzZW1lbnQgw6AgZGVzIGNhdMOpZ29yaWVzIHN0YXRpc3RpcXVlcyBjb25zYWNyw6llc8KgOiBkZXMgcHVyaXN0ZXMgcG91cnJhaWVudCBpY2kgYXJndWVyIG5vdGFtbWVudCBxdWUgbG9yc3F1J2lsIHMnYWdpdCBkZSBub21icmVzIGVudGllcnMsIGNvbW1lIGxlcyBpZGVudGlmaWFudHMgb3UgbGVzIGRhdGVzIHNvdXMgbGEgZm9ybWUgZCdhbm7DqWVzLCBvbiBlc3QgZW4gdGVybWlub2xvZ2llIG1hdGjDqW1hdGlxdWUgZmFjZSDDoCBkZXMgdmFyaWFibGVzIHF1J2lsIGZhdWRyYWl0IGRpcmUgZGlzY3LDqHRlcyBwbHV0w7R0IHF1ZSBjb250aW51ZXMuIFF1J2ltcG9ydGUsIGNlbGEgcGFyYcOudCBkZSBwZXUgZCdpbXBvcnRhbmNlIHBvdXIgY2UgcXVpIG5vdXMgcHLDqW9jY3VwZSBpY2kuKQ0KDQotIExlcyB2YXJpYWJsZXMgIioqY2F0w6lnb3JpZWxsZXMqKiLCoDogaWwgcydhZ2l0IGRlICJjYXTDqWdvcmllcyIgZGFucyBsZXNxdWVsbGVzIG9uIHJhbmdlIGxlcyBpbmRpdmlkdXMsIGRlcyBzb3J0ZXMgZCfDqXRpcXVldHRlcywgZW4gbm9tYnJlIGxpbWl0w6ksIHF1J29uIGFwcGxpcXVlIGNoYWN1bmUgw6AgcGx1c2lldXJzIGluZGl2aWR1cy4gRGFucyBub3RyZSBjYXMsIGVsbGVzIHNlcm9udCBzb3VzIGxhIGZvcm1lIGRlIGNoYcOubmVzIGRlIGNhcmFjdMOocmVzLiBJbCBzJ2FnaXQgcGFyIGV4ZW1wbGUgZGVzIGdlbnJlcyBsaXR0w6lyYWlyZXMgb3UgZGVzIGxpZXV4LiBMZXMgaW5pdGlhbGVzIGRlcyBub21zIHBldXZlbnQgw6lnYWxlbWVudCBlbiByZWxldmVyLg0KDQotIExlcyB2YXJpYWJsZXMgIioqc2luZ3VsacOocmVzKioiwqA6IGlsIHMnYWdpdCBkZSB2YXJpYWJsZXMgZG9udCBsZSBjb250ZW51IGVzdCBzaW5ndWxpZXIsIGV0IGfDqW7DqXJhbGVtZW50IHVuaXF1ZSwgw6AgY2hhcXVlIGluZGl2aWR1IGNvbnNpZMOpcsOpLiBUeXBpcXVlbWVudCwgYydlc3QgbGUgY2FzIGRlcyBub21zIGRlcyBhdXRldXJzLiBMYSBkaXN0aW5jdGlvbiBhdmVjIGxlcyB2YXJpYWJsZXMgY29udGludWVzIHJlcG9zZSBzdXIgbGUgZmFpdCBxdSdpbCBzJ2FnaXQgZGUgY2hhw65uZXMgZGUgY2FyYWN0w6hyZXMgcXUnaWwgZXN0IHBsdXMgZGlmZmljaWxlIGRlIHRyYW5zY3JpcmUgZW4gY2hpZmZyZXMsIGV0IGRvbmMgZG9udCBsYSBtYW5pcHVsYXRpb24gcGV1dCBkaWZmw6lyZXIuDQoNCkxlcyB2YXJpYWJsZXMgY29udGludWVzIHByw6lzZW50ZW50IGwnYXZhbnRhZ2UgZGUgY29ycmVzcG9uZHJlIMOgIHVuZSDDqWNoZWxsZSBkw6l0ZXJtaW7DqWXCoDogb24gcGV1dCBmYWNpbGVtZW50IGRpcmUgcXVlIDMgZXN0IHN1cMOpcmlldXIgw6AgMSwgb3UgcXVlIC01MDAgZXN0IGFudMOpcmlldXIgw6AgLTQwMC4gTsOpYW5tb2lucywgbGVzIHZhcmlhYmxlcyBxdWUgbm91cyBhdm9ucyBhcHBlbMOpZXMgY2F0w6lnb3JpZWxsZXMgb3Ugc2luZ3VsacOocmVzLCBwZXV2ZW50IMOpZ2FsZW1lbnQgw6p0cmUgIioqb3Jkb25uw6llcyoqIiwgc2Vsb24gdW4gY3JpdMOocmUgZMOpdGVybWluw6nCoDogcG91ciBsZXMgbm9tcyBlbiBwYXJ0aWN1bGllciwgbCdvcmRyZSBhbHBoYWLDqXRpcXVlIHBhcmHDrnQgw6p0cmUgdW4gbW9kZSBkJ2FycmFuZ2VtZW50IHF1aSBmYWl0IHNlbnMuIFBvdXIgbGVzIGxpZXV4LCBvbiBwb3VycmFpdCBsZXMgcmFuZ2VyIHBhciBjYXTDqWdvcmllIGVtYm/DrnTDqWUgKHZpbGxlLCByw6lnaW9uLCBwYXlzKSwgb3UgZW5jb3JlIHNlbG9uIHVuIG9yZHJlIHBhcnRpY3VsaWVyIChwYXIgZXhlbXBsZSwgZCdvdWVzdCBlbiBlc3QpLiBDZXMgdmFyaWFibGVzICJvcmRvbm7DqWVzIiBzZSByYXBwcm9jaGVudCBhbG9ycyB1biBwZXUgZGVzIHZhcmlhYmxlcyBjb250aW51ZXMsIGNhciwgY29tbWUgY2VzIGRlcm5pw6hyZXMsIG9uIHBldXQgZMOpc29ybWFpcyBkaXJlIHNpIHRlbGxlIG1vZGFsaXTDqSB2aWVudCBhcHLDqHMgb3UgYXZhbnQgdGVsbGUgYXV0cmUgbW9kYWxpdMOpIGRhbnMgbCdvcmRyZSBxdSdvbiBhIGNob2lzacKgOiAiQXJpc3RvdGUiIHZpZW50IGF2YW50ICJQbGF0b24iIHBvdXIgbGEgdmFyaWFibGUgIm5vbSIgb3Jkb25uw6llIHBhciBvcmRyZSBhbHBoYWLDqXRpcXVlLg0KDQpOb3RvbnMgcXVlIG5vdXMgYXZvbnMgY2l0w6kgaWNpIGxlcyB2YXJpYWJsZXMgbGVzIHBsdXMgw6l2aWRlbnRlc8Kg4oCTIGV0IGxlcyBwbHVzIGFjY2Vzc2libGVzIOKAkyBxdWkgc2VtYmxlbnQgw6AgcHJlbWnDqHJlIHZ1ZSBwb3J0ZXIgbGUgcGx1cyBkZSBzZW5zIHBvdXIgbGEgcXVlc3Rpb24gcXVpIG5vdXMgcHLDqW9jY3VwZS4gTsOpYW5tb2lucywgaWwgc2UgcG91cnJhaXQgcXVlIG5vdXMgbGFpc3Npb25zIGFsb3JzIGRlIGPDtHTDqSBkJ2F1dHJlcyBjb25zaWTDqXJhdGlvbnMsIGNvbW1lIHBhciBleGVtcGxlIGRlcyBkYXRlcyBwYXJ0aWN1bGnDqHJlcywgZGUgZMOpY291dmVydGUgZGVzIG1hbnVzY3JpdHMgcGFyIGV4ZW1wbGXCoDsgb3UgZW5jb3JlLCBub3VzIHBvdXJyaW9ucyDDqnRyZSB0cm9wIHBldSBwcsOpY2lzIGVuIGNlIHF1aSBjb25jZXJuZSBsZSBub20gZGVzIGF1dGV1cnPCoDogcGV1dC3DqnRyZSBjZXV4LWNpIG9udC1pbCDDqXZvbHXDqSBkYW5zIGxlIHRlbXBzIGV0IGRhbnMgbCdlc3BhY2UsIHNlbG9uIGxlcyBsYW5ndWVzIGV0IGxlcyBhcHBlbGxhdGlvbnMsIG91IGJpZW4gcGV1dC3DqnRyZSBmYXVkcmFpdC1pbCDDqXRhYmxpciBkZXMgZGlzdGluY3Rpb25zIHNlbG9uIGNlIHF1aSBwb3VycmFpdCBjb3JyZXNwb25kcmUgw6AgZGVzIMOpbMOpbWVudHMgY29tbWUgbGUgbm9tIGV0IGxlIHByw6lub20sIGVuIGNvbnN0aXR1YW50IGFsb3JzIGRlcyBzb3VzLXZhcmlhYmxlcyBwbHVzIHByw6ljaXNlcy4NCg0KIyMjIFNhaXNpciBsZXMgY29ycsOpbGF0aW9ucw0KDQpQb3VyIGNvbXByZW5kcmUgbGVzIHJlbGF0aW9ucyBlbnRyZSBjZXMgdmFyaWFibGVzLCBub3RhbW1lbnQgcG91ciBkw6l0ZXJtaW5lciBzaSBlbGxlcyBzb250IGNvcnLDqWzDqWVzIG91IG5vbiwgZXQgc2kgb3VpLCBkZSBxdWVsbGUgbWFuacOocmUsIG5vdXMgYWxsb25zIG1vYmlsaXNlciBkZXMgYW5hbHlzZXMgKipncmFwaGlxdWVzKirCoDogcGx1dMO0dCBxdWUgZGVzIGFuYWx5c2VzIG1hdGjDqW1hdGlxdWVzIMOgIGwnYXZldWdsZXR0ZSwgbGVzIGdyYXBoaXF1ZXMgcGFyYWlzc2VudCBvZmZyaXIgbCdhcHByb2NoZSBsYSBwbHVzIGZsZXhpYmxlIGV0IGNvbXByw6loZW5zaXZlLiBOb3VzIHBvdXJyb25zIGFsb3JzIHByb2pldGVyIGxlcyB2YXJpYWJsZXMgc3VyIGxlcyBheGVzLCBkJ3VuIHBsYW4gaGFiaXR1ZWwgZW4gZGV1eCBkaW1lbnNpb25zLCBldCDDqXZlbnR1ZWxsZW1lbnQgdXNlciBkZSBjb3VsZXVycyBwb3VyIGZhaXJlIGFwcGFyYcOudHJlIMOgIHRyYXZlcnMgZWxsZXMgdW5lIHRyb2lzacOobWUgZGltZW5zaW9uLg0KDQpJbCBmYXV0IG5vdGVyIHF1ZSBub3VzIGRldnJvbnMgKmEgcHJpb3JpKiB0b3Vqb3VycyBwcm9qZXRlciBsYSB2YXJpYWJsZSDDoCBleHBsaXF1ZXIsIGMnZXN0LcOgLWRpcmUgY2VsbGUgZGVzIGlkZW50aWZpYW50cyAow6AgbW9pbnMgcXVlIG5vdXMgbmUgY2hlcmNoaW9ucyDDoCBkaXN0aW5ndWVyIGRlcyBjb3Jyw6lsYXRpb25zIGludGVybcOpZGlhaXJlcyBxdWkgc29udCBsYSBjYXVzZSBwcmVtacOocmUgZGVzIHJlbGF0aW9ucyBvYnNlcnbDqWVzwqDigJMgcGFyIGV4ZW1wbGUgc2kgbGUgbGlldSBlc3QgY29ycsOpbMOpIGF2ZWMgbGEgZGF0ZSwgb24gcG91cnJhaXQsIGVuIG5lIHJlZ2FyZGFudCBxdWUgbGVzIGlkZW50aWZpYW50cyBldCBsZXMgbGlldXgsIHBlbnNlciBxdSdpbCB5IGEgY29ycsOpbGF0aW9uLCBxdWFuZCBsYSB2w6lyaXRhYmxlIGNvcnLDqWxhdGlvbiBzZXJhaXQgZW4gcsOpYWxpdMOpIGVudHJlIGxlcyBpZGVudGlmaWFudHMgZXQgbGVzIGRhdGVzKS4NCg0KKkEgcHJpb3JpKiwgbGVzIHZhcmlhYmxlcyBjb250aW51ZXMgc2UgcHLDqnRlbnQgYmllbiDDoCBsYSBwcm9qZWN0aW9uIHN1ciB1biAqKmF4ZSoqIG9yaWVudMOpLCBjYXIgZWxsZXMgY29ycmVzcG9uZGVudCDDoCB1bmUgw6ljaGVsbGUuIENlbGEgZXN0IHZyYWkgYXVzc2ksIHF1b2lxdWUgZGFucyB1bmUgbW9pbmRyZSBtZXN1cmUsIHBvdXIgbGVzIHZhcmlhYmxlcyBvcmRvbm7DqWVzLCBkb250IGwnb3JkcmUgcGV1dCBhcHBhcmHDrnRyZSBhdSBmaWwgZGUgbCdheGUuIExlcyB2YXJpYWJsZXMgY2F0w6lnb3JpZWxsZXMgKG9yZG9ubsOpZXMgb3Ugbm9uKSBxdWFudCDDoCBlbGxlcyBzZSBwcsOqdGVudCBiaWVuIMOgIGwndXRpbGlzYXRpb24gZGUgKipjb3VsZXVycyoqLCBkdSBmYWl0IHF1J2VsbGVzIGRldnJhaWVudCDDqnRyZSByZWxhdGl2ZW1lbnQgcGV1IG5vbWJyZXVzZXMsIGV0IGRvbmMgZGlzdGluZ3VhYmxlcyBncsOiY2Ugw6AgZGVzIGNvdWxldXJzIGRpZmbDqXJlbnRlcy4gTG9yc3F1J2VsbGVzIHNvbnQgb3Jkb25uw6llcyAodm9pcmUsIGRhbnMgdW4gYXV0cmUgc3R5bGUsIHF1YW5kIG9uIGEgw6AgZmFpcmUgw6AgZGVzIHZhcmlhYmxlcyBjb250aW51ZXMpLCBvbiBwb3VycmFpdCBkZSBwbHVzIGZhaXJlIGFwcGVsIMOgIHVuIGTDqWdyYWTDqcKg4oCTIHBhciBleGVtcGxlLCBlbiBhdHRyaWJ1YW50IGRlcyBjb3VsZXVycyBwbHVzIGNsYWlyZXMgYXV4IHZhbGV1cnMgImluZsOpcmlldXJlcyIsIGV0IGRlcyBjb3VsZXVycyBwbHVzIHNvbWJyZXMgYXV4IHZhbGV1cnMgInN1cMOpcmlldXJlcyIuDQoNCkwnYWpvdXQgZCd1bmUgdHJvaXNpw6htZSBkaW1lbnNpb24gcGFyIGxhIGNvdWxldXIgcG91cnJhIG5vdXMgYWlkZXIgw6AgZGlzdGluZ3VlciB1bmUgw6l2b2x1dGlvbiBkYW5zIGxlIGNhcyBvw7kgbGEgY2xhc3NpZmljYXRpb24gY2hhbmdlcmFpdCBkZSBsb2dpcXVlIGVuIGNvdXJzIGRlIHJvdXRlLCBvdSBvYsOpaXJhaXQgZW4gZmFpdCDDoCBwbHVzaWV1cnMgbG9naXF1ZXPCoDogcGFyIGV4ZW1wbGUsIHNpIGxlcyBhdXRldXJzIMOpdGFpZW50IHJlZ3JvdXDDqXMgcGFyIGxpZXUsIHB1aXMsIGF1IHNlaW4gZGUgY2hhcXVlIGdyb3VwZSBjb25zdGl0dcOpIHBvdXIgdW4gbGlldSBkb25uw6ksIHF1J2lscyDDqXRhaWVudCBjbGFzc8OpcyBwYXIgb3JkcmUgYWxwaGFiw6l0aXF1ZS4gT24gdmVycmFpdCBhaW5zaSwgc3VyIG5vcyBncmFwaGlxdWVzLCBzb2l0IGRlcyBzw6lxdWVuY2VzIGQnw6lsw6ltZW50cyBxdWkgc2Ugc3VpdmVudCBkYW5zIGwnb3JkcmUgYWxwaGFiw6l0aXF1ZSwgY2hhY3VuZSBkJ3VuZSBjb3VsZXVyIHBhcnRpY3VsacOocmUgKHNpIG9uIHByb2pldHRlIGxlIG5vbSBzdXIgdW4gYXhlLCBldCBxdSdvbiBjb2xvcmUgbGVzIGxpZXV4KSwgc29pdCBkZXMgcG9pbnRzIHJlZ3JvdXDDqXMgZW5zZW1ibGUgcGFyIGxpZXUsIGF2ZWMgc3VyIGNoYWN1biB1biBkw6lncmFkw6kgZGUgY291bGV1cnMgY29ycmVzcG9uZGFudCDDoCBsJ29yZHJlIGFscGhhYsOpdGlxdWUgKHNpIG9uIHByb2pldHRlIGxlcyBsaWV1eCBzdXIgdW4gYXhlLCBldCBxdSdvbiBjb2xvcmUgbGVzIGluaXRpYWxlcykuDQoNCiMjIyDDiXRhcGVzIG7DqWNlc3NhaXJlcw0KDQpOb3VzIGRldnJvbnMgY29uc3RpdHVlciBub3MgZG9ubsOpZXMsIGVuIHLDqWN1cMOpcmFudCBsZXMgaW5mb3JtYXRpb25zIGFwcHJvcHJpw6llcyAoY29ycmVzcG9uZGFuY2UgZW50cmUgaWRlbnRpZmlhbnRzIGV0IG5vbXMgZGVzIGF1dGV1cnMsIGRhdGVzIGRlcyBhdXRldXJzLCBnZW5yZSBsaXR0w6lyYWlyZS4uLiksIHB1aXMgZmFpcmUgZW4gc29ydGUgZGUgbGVzIHRyYWl0ZXIuIFN1Y2Nlc3NpdmVtZW50LCBub3VzIGRldnJvbnPCoDoNCg0KMC4gKipSw6ljdXDDqXJlciBkZXMgZG9ubsOpZXMqKiAodm9pciBbQ2hhcmdlbWVudCBkZXMgZG9ubsOpZXNdKCNjaGFyZ2VtZW50LWRlcy1kb25uw6llcykpLCBkZXB1aXMgaW50ZXJuZXQgbm90YW1tZW50LCDDoCBwYXJ0aXIgZGUgYmFzZXMgZGUgZG9ubsOpZXMgZMOpasOgIGNvbnN0aXR1w6llc8KgOw0KDQoxLiAqKkZvcm1hdGVyIGNlcyBkb25uw6llcyoqIHBvdXIgbGVzIHJlbmRyZSBleHBsb2l0YWJsZXMgKHZvaXIgWzEuIEZvcm1hdGFnZSBkZXMgZG9ubsOpZXNdKCNmb3JtYXRhZ2UtZGVzLWRvbm7DqWVzKSksIG5vdGFtbWVudCBlbiBzJ2Fzc3VyYW50IGRlIGwnaG9tb2fDqW7DqWl0w6kgZGVzIGNhdMOpZ29yaWVzIGV0IGVuIHRyYW5zZm9ybWFudCBjZXJ0YWluZXMgdmFyaWFibGVzIHRleHR1ZWxsZXMgZW4gdmFyaWFibGVzIG51bcOpcmlxdWVzwqA7DQoNCjIuICoqUsOpYWxpc2VyIGRlcyBhbmFseXNlcyoqIMOgIHBhcnRpciBkZXMgZG9ubsOpZXMgZm9ybWF0w6llcyAodm9pciBbMi4gQW5hbHlzZXMgZ3JhcGhpcXVlc10oI2FuYWx5c2VzLWdyYXBoaXF1ZXMpKSwgYydlc3Qtw6AtZGlyZSwgaWNpLCBlc3NlbnRpZWxsZW1lbnQgZGVzIGdyYXBoaXF1ZXMuDQoNCiMjIFByw6lwYXJhdGlmcw0KDQojIyMgQ29uZmlndXJhdGlvbiBnw6luw6lyYWxlDQoNCipDaGFyZ2VtZW50IGRlcyBiaWJsaW90aMOocXVlcyBleHRlcm5lcy4qDQpgYGB7ciBsb2FkaW5nLXBhY2thZ2VzfQ0KcGFjbWFuOjpwX2xvYWQoDQogIGhlcmUsIGpzb25saXRlLCBrbml0ciwgc2tpbXIsIHRpZHl2ZXJzZQ0KKQ0KYGBgDQoNCipDb25maWd1cmF0aW9uIGR1IHJlbmR1LioNCmBgYHtyIGNvbmZpZy1rbml0ciwgd3JhcHBlciA9IFRSVUV9DQojIERpc2FibGUgZ2xvYmFsbHkgc29tZSBtZXNzYWdlcyBpbiB0aGUgZmluYWwgcmVuZGVyaW5nLA0KIyBzdWNoIGFzIG1pbm9yIHdhcm5pbmdzIGZyb20gZXh0ZXJuYWwgZnVuY3Rpb25zLg0Kb3B0c19jaHVuayRzZXQoDQogIG1lc3NhZ2UgPSBGQUxTRSwNCiAgd2FybmluZyA9IEZBTFNFDQopDQoNCmRlZmF1bHRfY29sc19uYiA8LSAxMg0KIycgUHJpbnQgYSB2ZWN0b3IgYXMgYSBrYWJsZS4NCiMnIEFsbG93cyB0byBmaXggYXV0by13cmFwcGVkIHByaW50ZWQgdmVjdG9yLg0KIycgQHBhcmFtIGRhdGEgVmVjdG9yIG9mIGRhdGEgdG8gcHJpbnQuDQojJyBAcGFyYW0gY29sc19uYiBJbnRlZ2VyLiBEZXNpcmVkIG51bWJlciBvZiBjb2x1bW5zLg0KIycgQHJldHVybiBOVUxMIFByaW50cyB0aGUgdGFibGUgYXMgYSBrbml0cjo6a2FibGUuDQpwcmludF92ZWN0b3IgPC0gZnVuY3Rpb24oZGF0YSwgY29sc19uYiA9IGRlZmF1bHRfY29sc19uYikgew0KICB0aWJibGUodmFsID0gZGF0YSkgJT4lDQogICAgcm93aWRfdG9fY29sdW1uKCkgJT4lDQogICAgbXV0YXRlKA0KICAgICAgZ3JvdXAgPSByb3dpZCAlJSBjb2xzX25iLA0KICAgICAgbmV3X3Jvd2lkID0gY2VpbGluZyhyb3dpZCAvIGNvbHNfbmIpDQogICAgKSAlPiUNCiAgICBzZWxlY3QoLXJvd2lkKSAlPiUNCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZ3JvdXAsIHZhbHVlc19mcm9tID0gdmFsKSAlPiUNCiAgICBzZWxlY3QoLW5ld19yb3dpZCkgJT4lDQogICAgbXV0YXRlX2FsbCgNCiAgICAgIH4gcmVwbGFjZV9uYSguLCAiIikNCiAgICApICU+JSANCiAgICBrbml0cjo6a2FibGUoDQogICAgICBjb2wubmFtZXMgPSBjKCkNCiAgICApDQp9DQpgYGANCg0KKkTDqWNsYXJhdGlvbiBkZSB2YXJpYWJsZXMgZ2xvYmFsZXMgKHF1J29uIHBvdXJyYWl0IGF1c3NpIGFwcGVsZXIgZGVzIGNvbnN0YW50ZXMpLioNCmBgYHtyIGNvbnN0YW50c30NCiMgSW5wdXQgZGlyZWN0b3J5Lg0KaW5wdXRfZGlyIDwtIGhlcmUoInByb2pldF9maW5hbC9kYXRhLyIpDQojIE9uIFdpbmRvd3MsIHRoZSAnaGVyZScgcGFja2FnZSBkZWxldGVzIHRoZSBmaW5hbCAiLyIgYWx0aG91Z2ggd2UgbmVlZCBpdCwgdGhlcmVmb3JlIHdlIG11c3QgYWRkIGl0IGFnYWluLg0KaWYgKC5QbGF0Zm9ybSRPUy50eXBlID09ICJ3aW5kb3dzIikgaW5wdXRfZGlyIDwtIHBhc3RlMChpbnB1dF9kaXIsICIvIikNCg0KIyBWYXJpYW50cyBmb3IgTkEgaW4gdGhlIHJldHJpZXZlZCBkYXRhLg0KbmFfdmFyaWFudHMgPC0gYygNCiAgIiIsICI/IiwgIlxuIiwgIi4uLiIsDQogICJOQSIsICJuLmEuIiwgIm4iLA0KICAibm9uZSIsICJOb25lIiwgIm9uZSIsDQogICJ1bmtub3duIiwgIlVua25vd24iLA0KICAiVmFyaW91cyIsICJWYXJpYSIsDQogICJVbmNlcnRhaW4iDQopDQoNCiMgTm90ZSB0aGF0IHdlIHdpbGwgZGVjbGFyZSBjb2xvcnMgaW4gcmVsZXZhbnQgc2VjdGlvbiB0byBwcmVzZW50IHRoZW0sDQojIHdoaWNoIGlzIGluIHRoZSBtaWRkbGUgb2YgdGhlIHNlY29uZCBzZWN0aW9uLg0KYGBgDQoNCk5vdXMgZMOpY2xhcm9ucyBjaS1kZXNzdXMgdW5lIGZvaXMgcG91ciB0b3V0ZXMgbGVzIGRpZmbDqXJlbnRlcyBjaGHDrm5lcyBkZSBjYXJhY3TDqHJlcyBwb3V2YW50IMOqdHJlIHV0aWxpc8OpZXMgcG91ciBpbmRpcXVlciBkZXMgKipkb25uw6llcyBtYW5xdWFudGVzKiosIGRhbnMgbGVzIGRpZmbDqXJlbnRlcyB2YXJpYWJsZXMgZGVzIGRvbm7DqWVzIG9yaWdpbmFsZXMsIHJlcMOpcsOpZXMgYXUgZmlsIGRlIG5vcyBleHBsb3JhdGlvbnMuIEVsbGVzIHNlcm9udCByZW1wbGFjw6llcyBlbiB1bmUgZm9pcyBhdSBkw6lidXQgZHUgZm9ybWF0YWdlIGRlcyBkb25uw6llcy4NCg0KIyMjIENoYXJnZW1lbnQgZGVzIGRvbm7DqWVzDQoNCkxhIHBsdXBhcnQgZGVzIGRvbm7DqWVzIHF1ZSBub3VzIG1vYmlsaXNvbnMgc29udCByw6ljdXDDqXLDqWVzIGRlcHVpcyB1biBbdGFibGV1ciBlbiBsaWduZSBkdSAqUHJvamV0IFBlcnNldXMqXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xUkhONktCdWxER2JwS0FUTFU2UHR3VTRvNXhWc2FCQjZ4YlFSdEtqTXlXRS9lZGl0KS4gTGUgdGFibGV1ciBjb250aWVudCBkZXMgZW50csOpZXMgZCfFk3V2cmVzIGFudGlxdWVzLCBhaW5zaSBxdWUgZGVzIGluZm9ybWF0aW9ucyBzdXIgbGV1cnMgYXV0ZXVycyBxdWkgcG91cnJhaWVudCBub3VzIMOqdHJlIHV0aWxlcywgZW4gcGFydGljdWxpZXLCoDogbm9tLCBsaWV1LCBkYXRlcyBkJ2FjdGl2aXTDqSwgZGUgImTDqWJ1dCIgZXQgZGUgImZpbiIuIElsIGNvbnRpZW50IMOpZ2FsZW1lbnQgbGVzIGlkZW50aWZpYW50cyBxdSdvbiBjaGVyY2hlIMOgIGV4cGxpcXVlciwgw6Agc2F2b2lyIGxlcyBpZGVudGlmaWFudHMgVExHIGV0IFBISS4NCg0KYGBge3IgbG9hZGluZy1kYXRhLCB3YXJuaW5nID0gRkFMU0V9DQpwaGlfd29ya3NfcmF3X2RmIDwtIHJlYWRfY3N2KHBhc3RlMChpbnB1dF9kaXIsICJsYXRpbl9hdXRob3JzX2J5LXBlcnNldXMuY3N2IikpDQp0bGdfd29ya3NfcmF3X2RmIDwtIHJlYWRfY3N2KHBhc3RlMChpbnB1dF9kaXIsICJncmVla19hdXRob3JzX2J5LXBlcnNldXMuY3N2IikpDQpgYGANCg0KRW4gY29tcGzDqW1lbnQsIG5vdXMgdXRpbGlzZXJvbnMgbGEgbGlzdGUgZGVzIGdlbnJlcyByw6ljdXDDqXLDqWUgZGVwdWlzIGxlcyBmaWNoaWVycyBkdSBbQ0xUS10oaHR0cHM6Ly9naXRodWIuY29tL2NsdGsvY2x0ay9ibG9iL21hc3Rlci9jbHRrL2NvcnB1cy9ncmVlay90bGcvYXV0aG9yX2VwaXRoZXQuanNvbikgKCpDbGFzc2ljYWwgTGFuZ3VhZ2UgVG9vbEtpdCosIGxhIGJvw650ZSDDoCBvdXRpbHMgZGVzIGxhbmd1ZXMgY2xhc3NpcXVlcykuIElsIG5lIHMnYWdpdCBpY2kgcXVlIGRlcyBhdXRldXJzIGdyZWNzwqDigJMgaWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlIGRlIHLDqWN1cMOpcmVyIGwnw6lwaXRow6h0ZSBkZSBnZW5yZSBzdXIgbGVzIG5vbXMgZGVzIGF1dGV1cnMgVExHIHRlbHMgcXUnaWxzIHNvbnQgZm9ybWF0w6lzIGRhbnMgbGEgbGlzdGUgZHUgUHJvamV0IFBlcnNldXMsIG1haXMgYXV0YW50IHByb2ZpdGVyIGRlIGNlIGZvcm1hdGFnZSBkw6lqw6Agw6l0YWJsaS4NCg0KYGBge3IgbG9hZGluZy1kYXRhLWVwaXRoZXRzfQ0KdGxnX2VwaXRoZXRzX3Jhd19kZiA8LQ0KICByZWFkX2pzb24ocGFzdGUwKGlucHV0X2RpciwgImdyZWVrX2F1dGhvcnMtZXBpdGhldHNfYnktY2x0ay5qc29uIikpICU+JQ0KICBlbmZyYW1lKCJnZW5yZSIsICJjb2RlIikNCmBgYA0KDQpOb3RvbnMgcXVlIG5vdXMgY29uc2VydmVyb25zLCBkYW5zIGwnZW52aXJvbm5lbWVudCBkZSBkw6l2ZWxvcHBlbWVudCwgbGVzIHRhYmxlYXV4IGF2ZWMgbGVzIGRvbm7DqWVzIGQnb3JpZ2luZSBjaGFyZ8OpcyBpY2nCoDogY2VsYSBub3VzIHBlcm1ldHRyYSBlbiBlZmZldCwgYXUgY291cnMgZHUgZMOpdmVsb3BwZW1lbnQgZGUgbm9zIGFuYWx5c2VzLCBkJ8OpdmVudHVlbGxlbWVudCBhbGxlciB2w6lyaWZpZXIgcXVlbGxlcyDDqXRhaWVudCBsZXMgZG9ubsOpZXMgZGUgYmFzZSBjb3JyZXNwb25kYW50ZXMuDQoNCiMjIDEuIEZvcm1hdGFnZSBkZXMgZG9ubsOpZXMNCg0KIyMjIFZhcmlhYmxlcyByZWNoZXJjaMOpZXMNCg0KKlBvdXIgY29uc3VsdGVyIGxlcyBkb25uw6llcyBmaW5hbGVzIG9idGVudWVzLCByZW5kZXotdm91cyBbw6AgbGEgZmluIGRlIGxhIHNlY3Rpb25dKCNkb25uw6llcy1maW5hbGVzLW9idGVudWVzKSAhKg0KDQpQb3VyIHJlbmRyZSBsZXMgZG9ubsOpZXMgcsOpY3Vww6lyw6llcyBleHBsb2l0YWJsZXMsIG5vdXMgZGV2b25zIGVuIGZvcm1hbGlzZXIgbGEgc3RydWN0dXJlIGVuIGxlcyAiZW5jb2RhbnQiIGRlIHNvcnRlIHF1J2VsbGVzIGNvcnJlc3BvbmRlbnQgYXV4IGFuYWx5c2VzIHF1ZSBub3VzIHNvdWhhaXRvbnMgbWVuZXIuDQoNCkVuIGZpbiBkZSBjb21wdGUsIGxlcyB2YXJpYWJsZXMgcXVlIG5vdXMgb2J0aWVuZHJvbnMgc2Vyb250IGxlcyBzdWl2YW50ZXPCoDoNCg0KfCBOb20gfCBEZXNjcmlwdGlvbiB8IEV4ZW1wbGUgfCBOYXR1cmUgfCBUeXBlIHwgU291cmNlIGQnb3JpZ2luZSB8DQp8LS0tOnwtLS18LS0tfC0tLXwtLS18LS0tfA0KfCBgY29kZWAgfCBpZGVudGlmaWFudCB8IGAwMDU5YCB8IG5vbWJyZSB8IGNvbnRpbnVlIHwgW1BlcnNldXNdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFSSE42S0J1bERHYnBLQVRMVTZQdHdVNG81eFZzYUJCNnhiUVJ0S2pNeVdFL2VkaXQpIHwNCnwgYGluaXRgIHwgaW5pdGlhbGUqIHwgYFBgIHwgY2FyYWN0w6hyZSB8IGNhdMOpZ29yaWVsbGU8YnI+b3Jkb25uw6llIHwgUHJlbWnDqHJlIGxldHRyZTxicj5kZSAibm9tIiB8DQp8IGBuYW1lYCB8IG5vbSogfCBgUGxhdG8gUGhpbC5gIHwgY2FyYWN0w6hyZXMgfCBzaW5ndWxpw6hyZTxicj5vcmRvbm7DqWUgfCBbUGVyc2V1c10oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVJITjZLQnVsREdicEtBVExVNlB0d1U0bzV4VnNhQkI2eGJRUnRLak15V0UvZWRpdCkgfA0KfCBgZ2VucmVgIHwgZ2VucmUgbGl0dMOpcmFpcmU8YnI+KCpUTEcgdW5pcXVlbWVudCopIHwgYFBoaWxvc29waGljaS8tYWVgIHwgY2FyYWN0w6hyZXMgfCBjYXTDqWdvcmllbGxlIHwgW0NMVEtdKGh0dHBzOi8vZ2l0aHViLmNvbS9jbHRrL2NsdGsvYmxvYi9tYXN0ZXIvY2x0ay9jb3JwdXMvZ3JlZWsvdGxnL2F1dGhvcl9lcGl0aGV0Lmpzb24pIHwNCnwgYHBsYWNlYCB8IGxpZXUgfCBgR3JlZWNlYCB8IGNhcmFjdMOocmVzIHwgY2F0w6lnb3JpZWxsZSB8IFtQZXJzZXVzXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xUkhONktCdWxER2JwS0FUTFU2UHR3VTRvNXhWc2FCQjZ4YlFSdEtqTXlXRS9lZGl0KSB8DQp8IGBkYXRlYCB8IGRhdGUgfCBgLTUwMGAgfCBub21icmUgfCBjb250aW51ZSoqIHwgQ29waWUgZGU8YnI+ImRhdGUgZCdhY3Rpdml0w6kiIHwNCnwgYGRhdGVfYWN0aXZlYCB8IGRhdGUgZCdhY3Rpdml0w6ksPGJyPm91IHNpw6hjbGUgfCBgLTUwMGAgfCBub21icmUgfCBjb250aW51ZSoqIHwgW1BlcnNldXNdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFSSE42S0J1bERHYnBLQVRMVTZQdHdVNG81eFZzYUJCNnhiUVJ0S2pNeVdFL2VkaXQpIHwNCnwgYGRhdGVfYmVnaW5gIHwgZGF0ZSAiZGUgZMOpcGFydCIsPGJyPm91IGRlIG5haXNzYW5jZSB8IGAtNDI3YCB8IG5vbWJyZSB8IGNvbnRpbnVlIHwgW1BlcnNldXNdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFSSE42S0J1bERHYnBLQVRMVTZQdHdVNG81eFZzYUJCNnhiUVJ0S2pNeVdFL2VkaXQpIHwNCnwgYGRhdGVfZW5kYCB8IGRhdGUgImRlIGZpbiIsPGJyPm91IGRlIG1vcnQgfCBgLTM0OGAgfCBub21icmUgfCBjb250aW51ZSB8IFtQZXJzZXVzXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xUkhONktCdWxER2JwS0FUTFU2UHR3VTRvNXhWc2FCQjZ4YlFSdEtqTXlXRS9lZGl0KSB8DQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO21hcmdpbi1ib3R0b206MTVweCI+KioqVGFibGVhdSBkZXMgdmFyaWFibGVzIHV0aWxpc8OpZXMqKio8L2Rpdj4NCg0KPGRpdiBzdHlsZT0iZm9udC1zaXplOnNtYWxsZXI7bWFyZ2luLWJvdHRvbToyMHB4Ij4oKikgTm91cyBzZXJvbnMgcGFyIGxhIHN1aXRlIGFtZW7DqXMsIGF1IGNvdXJzIGRlIG5vcyBhbmFseXNlcywgw6AgbW9kaWZpZXIgbGVzIG5vbXMsIGV0IHBhciBjb25zw6lxdWVudCBsZXMgaW5pdGlhbGVzLCBxdWkgbm91cyBzZXJ2ZW50IGRlIHLDqWbDqXJlbmNlLiBOb3VzIHRyYXZhaWxsZXJvbnMgYWxvcnMgc3VyIHVuZSBjb3BpZSBkdSB0YWJsZWF1IGQnb3JpZ2luZS48L2Rpdj4NCg0KPGRpdiBzdHlsZT0iZm9udC1zaXplOnNtYWxsZXI7bWFyZ2luLWJvdHRvbToyMHB4Ij4oKiopIExlIGNhcmFjdMOocmUgY29udGludSBkZSBsYSAiZGF0ZSBkJ2FjdGl2aXTDqSIgZXN0IGFtYmlndcKgOiBpbCBzJ2FnaXQgZW4gZWZmZXQgbGUgcGx1cyBzb3V2ZW50IGRlIHNpw6hjbGVzLCBzaSBiaWVuIHF1J29uIHBvdXJyYWl0IGNvbnNpZMOpcmVyIHF1J2lsIHMnYWdpdCBkJ3VuZSB2YXJpYWJsZSBjYXTDqWdvcmllbGxlIG9yZG9ubsOpZS4gTsOpYW5tb2lucywgcGFyIGNvbW1vZGl0w6ksIG5vdXMgbGEgdHJhaXRlcm9ucyBjb21tZSB1bmUgdmFyaWFibGUgcHJvcHJlbWVudCBudW3DqXJpcXVlLCBjJ2VzdC3DoC1kaXJlIGNvbnRpbnVlLjwvZGl2Pg0KDQpQb3VyIG9idGVuaXIgY2VzIGRvbm7DqWVzIGZpbmFsZXMsIGV4cGxvaXRhYmxlcyBzdGF0aXN0aXF1ZW1lbnQsIG5vdXMgYXZvbnMgZMO7IGZhaXJlIHBsdXNpZXVycyBjaG9peC4NCg0KLSBQb3VyIGxlcyAqKmRhdGVzKiosIG5vdXMgY29uc2Vydm9ucywgcG91ciBjaGFjdW5lIHN1cy1tZW50aW9ubsOpZSwgdW5lIHZhcmlhYmxlIMOpcXVpdmFsZW50ZSBzb3VzIGxhIGZvcm1lIGRlIGNoYcOubmUgZGUgY2FyYWN0w6hyZXMsIHBsdXMgZMOpdGFpbGzDqWUgZXQgcGx1cyBmaWTDqGxlIGF1eCBkb25uw6llcyBkZSBkw6lwYXJ0LCBtYWlzIHBsdXMgZGlmZmljaWxlbWVudCBleHBsb2l0YWJsZSBzdGF0aXN0aXF1ZW1lbnQgcGFyIGRlcyBncmFwaGlxdWVzLg0KDQogIENlcyDDqXF1aXZhbGVudHMtY2FyYWN0w6hyZXMgcmVzc2VtYmxlbnQgw6AgY2VjacKgOg0KDQogIC0gImAyMDBiY2U/YCIgY29ycmVzcG9uZCwgYXZlYyB1bmUgaW5jZXJ0aXR1ZGUgKGA/YCkgw6AgMjAwIGF2YW50IG5vdHJlIMOocmUgKGBiY2VgIHBvdXIgKkJlZm9yZSBDb21tb24gRXJhKiksIGV0IGVzdCB0cmFkdWl0IHNvdXMgZm9ybWUgbnVtw6lyaXF1ZSBlbiBgLTIwMGDCoDsNCg0KICAtICJgMTAwY2UtMjAwY2VgIiBkw6lzaWduZSB1biBpbnRlcnZhbGxlIGNvbXByaXMgZW50cmUgMTAwIGV0IDIwMCBkZSBub3RyZSDDqHJlIChgY2VgIHBvdXIgKkNvbW1vbiBFcmEqKS4gTm91cyBwcmVub25zIGFsb3JzIGxhIG1veWVubmUgZGVzIGRldXggZXh0csOpbWl0w6lzLCBjZSBxdWUgbm91cyBkb25uZSBgMTUwYC4NCg0KLSBFbiBjZSBxdWkgY29uY2VybmUgbGUgIioqc2nDqGNsZSoqIiwgbGUgZmFpdCBkZSBwcmVuZHJlIGxhIG1veWVubmUgbG9yc3F1J29uIGVzdCBmYWNlIMOgIHVuIGludGVydmFsbGUgYnJpc2UgbCdob21vZ8OpbsOpaXTDqSBkZSBsYSBtZXN1cmUuICJgMTAwY2UtMjAwY2VgIiBjb3JyZXNwb25kIMOgICJlbnRyZSBsZSBwcmVtaWVyIGV0IGxlIHNlY29uZCBzacOoY2xlIiwgbsOpYW5tb2lucyAiYDE1MGAiIG5lIGNvcnJlc3BvbmQgcGx1cyDDoCB1biBzacOoY2xlLCBtYWlzIHBsdXTDtHQgw6AgdW4gZGVtaS1zacOoY2xlLg0KRGUgcGx1cywgbm91cyBhdm9ucyB1biBwcm9ibMOobWUgYXUgdG91cm5hbnQgZGUgbCfDqHJlwqA6ICJgMTAwYmNlYCIgY29ycmVzcG9uZCBhdSBwcmVtaWVyIHNpw6hjbGUgYXZhbnQgKGFubsOpZXMgLTEwMCDDoCAtMSkgZXQgImAxMDBjZWAiIGF1IHByZW1pZXIgc2nDqGNsZSBhcHLDqHMgKGFubsOpZXMgMSDDoCAxMDApwqA6IGwnw6ljaGVsbGUgZGVzIHNpw6hjbGVzIHBhc3NlIGRpcmVjdGVtZW50IGR1IC0xIGF1IDEsIHNhbnMgMCBpbnRlcm3DqWRpYWlyZSwgYWxvcnMgcXVlIGxhIGNvbnNpZMOpcmVyIGNvbW1lIHVuIG5vbWJyZSAibm9ybWFsIiBsYSBmYWl0IHBhc3NlciBwYXIgdW4gMC4NCg0KICBDZSBkZXJuaWVyIHNvdWNpIMOpdGFudCBkZSBwZXUgZCdpbXBvcnRhbmNlIGV0IG5vbiDDqXZpZGVudCDDoCBjb3JyaWdlciwgbm91cyBzaWduYWxvbnMgc2ltcGxlbWVudCBxdWUgbGVzIGRhdGVzIGVudHJlIC0xMDAgZXQgMTAwLCBxdWFuZCBub3VzIHByZW5kcm9ucyBsZXMgc2nDqGNsZXMgKGBkYXRlX2FjdGl2ZWAgb3UgYGRhdGVgKSwgc2Vyb250IMOpdGFsw6llcyBkZXV4IGZvaXMgcGx1cyBxdWUgcmVsYXRpdmVtZW50IMOgIGRlcyBkb25uw6llcyBjb3JyZWN0ZW1lbnQgaG9tb2fDqG5lcy4NCg0KLSBQb3VyIGxlcyAqKmxpZXV4KiosIG5vdXMgbidhdm9ucyBjb25zZXJ2w6kgcXVlIGxlIHBheXMsIHBvdXIgZ2FnbmVyIGVuIGfDqW7DqXJhbGl0w6kgZXQgYXZvaXIgZGVzIGNhdMOpZ29yaWVzIHBsdXMgYW1wbGVzwqDigJMgbGVzIGRvbm7DqWVzIGRlIGTDqXBhcnQgY29tcG9ydGFpZW50IMOpZ2FsZW1lbnQgcGFyZm9pcyBsYSByw6lnaW9uIGV0L291IGxhIHZpbGxlLg0KDQogIExvcnNxdWUgcGx1c2lldXJzIGxpZXV4IMOpdGFpZW50IGluZGlxdcOpcywgbm91cyBuJ2F2b25zIGFyYml0cmFpcmVtZW50IGNvbnNlcnbDqSBxdWUgbGUgZGVybmllciBkZSBsYSBsaXN0ZS4gSWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlLCBtYWlzIGFsb3JzIHBsdXMgZmFzdGlkaWV1eCwgZGUgcsOpY3Vww6lyZXIgY2VzIGxpZXV4IG11bHRpcGxlcyBwb3VyIGxlcyBmb3JtYXRlciBjb252ZW5hYmxlbWVudCwgZW4gbGVzIGF0dHJpYnVhbnQgw6AgY2hhcXVlIGF1dGV1ciBzb3VzIGxhIGZvcm1lIGQndW4gb2JqZXQgImxpc3RlIiwgcG91ciBlbnN1aXRlIGR1cGxpcXVlciBjaGFxdWUgbGlnbmUgY29udGVuYW50IHBsdXNpZXVycyBsaWV1eC4gQ2VsYSBub3VzIGF1cmFpdCBwZXJtaXMgZGUgZmFpcmUgdW5lIGFuYWx5c2UgcGx1cyBjb21wbMOodGUgZGVzIGxpZXV4wqA7IHVuIG3Dqm1lIGF1dGV1ciBhdmVjIHVuIHNldWwgaWRlbnRpZmlhbnQgYXVyYWl0IGFsb3JzIHB1IMOqdHJlIHJlcHLDqXNlbnTDqSBwYXIgcGx1c2lldXJzIHBvaW50cywgZGUgc29ydGUgcXUnaWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlIGRlIHJlcMOpcmVyLCBzdXIgbGVzIG51YWdlcyBkZSBwb2ludHMsIGxlIGxpZXUgImFiZXJyYW50IiBldCBsZSBsaWV1ICJjb3JyZWN0IiB2aXMtw6AtdmlzIGRlIGxhIGxvZ2lxdWUgZG9taW5hbnRlIHF1aSBzZSBzZXJhaXQgZMOpZ2Fnw6llLg0KDQogIE5vdXMgYXZvbnMgw6lnYWxlbWVudCByZWxldsOpLCBtYWlzIHNhbnMgeSBhcHBsaXF1ZXIgdW4gdHJhaXRlbWVudCBwYXJ0aWN1bGllciwgcXUnaWwgcG91dmFpdCBleGlzdGVyIGRpdmVyc2VzIGFwcGVsbGF0aW9ucyBwb3VyIHVuIGVzcGFjZSBnw6lvZ3JhcGhpcXVlIGlkZW50aXF1ZSwgZW4gdG90YWxpdMOpIG91IGVuIHBhcnRpZS4gUGFyIGV4ZW1wbGUsIG5vdXMgb2JzZXJ2b25zIGxlcyBtb2RhbGl0w6lzICIqSW9uaWEqIiwgIipUdXJrZXkqIiwgIipBbmF0b2xpYSoiIG91IGVuY29yZSAiKlR1bmlzaWEqIiwgIipOb3J0aCBBZnJpY2EqIiwgIipBZnJpY2EqIi4gQ2VzIGTDqXNpZ25hdGlvbnMgc29udCBwcm9iYWJsZW1lbnQgbGnDqWVzIGVuIHBhcnRpZSDDoCBsJ8OpcG9xdWUgw6AgbGFxdWVsbGUgYXBwYXJ0aWVudCBsJ2F1dGV1ciA6IHBhciBleGVtcGxlLCAiKklvbmlhKiIgc2VyYWl0IHBsdXTDtHQgbCdhcHBlbGxhdGlvbiBlbXBsb3nDqWUgcG91ciBsZXMgcG/DqHRlcyBhcmNoYcOvcXVlcyBldCBsZXMgcGhpbG9zb3BoZXMgcHLDqXNvY3JhdGlxdWVzLCBhbG9ycyBxdWUgIipUdXJrZXkqIiBjb3JyZXNwb25kcmFpdCBhdXggYXV0ZXVycyBjaHLDqXRpZW5zLiBDZXBlbmRhbnQsIGNldHRlIGV4cGxpY2F0aW9uIG5lIHNlbWJsZSBwYXMgcydhcHBsaXF1ZXIgw6AgdG91cyBsZXMgbGlldXggZXQgw6AgdG91cyBsZXMgYXV0ZXVycyBwdWlzcXVlLCBjb21tZSBub3VzIHBvdXJyb25zIGwnb2JzZXJ2ZXIgZGFucyBsZXMgZ3JhcGhpcXVlcyBkZXMgcGFyYWdyYXBoZXMgY29uc2FjcsOpcyBhdXggW2lkZW50aWZpYW50cyBldCBsaWV1eF0oI2lkZW50aWZpYW50cy1ldC1saWV1eCksIGxlIGxpZXUgIipUdXJrZXkqIiBjb25jZXJuZSBkZXMgYXV0ZXVycyBkw6hzIGxlIHF1YXRyacOobWUgc2nDqGNsZSBhdmFudCBub3RyZSDDqHJlLiBDb21wcmVuZHJlIGxhIGxvZ2lxdWUgcXVpIGEgY29uZHVpdCDDoCBkw6lzaWduZXIgY2VzIHRlcnJpdG9pcmVzIGVuIGZvbmN0aW9uIGRlcyBkYXRlcywgZXQgcGV1dC3DqnRyZSBkZXMgZ2VucmVzLCBwb3VycmFpdCBmYWlyZSBsJ29iamV0IGQndW5lIMOpdHVkZSDDoCBwYXJ0IGVudGnDqHJlLiBOb3VzIGF2b25zIGNlcGVuZGFudCBnYXJkw6kgbGVzIGTDqXNpZ25hdGlvbnMgZGUgbGlldXggdGVsbGVzIHF1ZSBub3VzIGxlcyBhdm9ucyByw6ljdXDDqXLDqWVzIGRhbnMgbm9zIGRvbm7DqWVzLg0KDQotIFBvdXIgbGVzICoqZ2VucmVzKiosIGxvcnNxdSd1biBhdXRldXIgYXBwYXJ0ZW5haXQgw6AgcGx1c2lldXJzIGdlbnJlcywgbm91cyBuJ2F2b25zIGNvbnNlcnbDqSBxdWUgbGUgcHJlbWllciBnZW5yZSBxdWkgYXBwYXJhaXNzYWl0IHBhciBvcmRyZSBhbHBoYWLDqXRpcXVlwqDigJMgZGUgbcOqbWUgcXVlIG5vdXMgdmVub25zIGRlIGwnZXhwbGljaXRlciBxdWFudCBhdXggbGlldXggbXVsdGlwbGVzLCBpbCBhdXJhaXQgYWx0ZXJuYXRpdmVtZW50IMOpdMOpIHBvc3NpYmxlIGQndXNlciBkJ29iamV0cyAibGlzdGUiLg0KDQotIE9uIHJlbWFycXVlcmEgZGFucyBsZSB0YWJsZWF1IGQnYXV0ZXVycyBncmVjcyBhdSBjaGFwaXRyZSBbIkRvbm7DqWVzIGZpbmFsZXMgb2J0ZW51ZXMiXSgjZG9ubsOpZXMtZmluYWxlcy1vYnRlbnVlcykgcXVlIGNlcnRhaW5zIGdlbnJlcyBsaXR0w6lyYWlyZXMgZmlndXJlbnQgZGFucyBsYSBjb2xvbm5lIGRlcyAqKm5vbXMgZCdhdXRldXJzKiogKGlzc3VlIGRlIFBlcnNldXMpIGFsb3JzIHF1J2VsbGVzIHNvbnQgbWFucXVhbnRlcyBkYW5zIGNlbGxlIGRlcyBnZW5yZXMgKGRhbnMgbGUgdGFibGVhdSBpbXBvcnTDqSBDTFRLKS4gVW5lIG9ic2VydmF0aW9uIHBsdXMgYXR0ZW50aXZlIHBlcm1ldCBjZXBlbmRhbnQgZGUgcmVtYXJxdWVyIHF1ZSBjZXMgImdlbnJlcyIgcXVpIGFwcGFyYWlzc2VudCBkYW5zIGxhIGNvbG9ubmUgKHBhciBleGVtcGxlICplcGlzdHVsYWUqKSBmb250IHBhcnRpZSBpbnTDqWdyYW50ZSBkZSBsYSB2YXJpYWJsZSBgbmFtZWDCoDsgaWxzIG5lIHNvbnQgcGFzIHF1YWxpZmlhbnRzIGQndW4gYXV0ZXVyLCBtYWlzIGTDqXNpZ25lbnQgdW4gY29ycHVzIHF1YWxpZmnDqSBwYXIgbGUgbm9tIGQndW4gYXV0ZXVyIC0gcsOpZWwsIGluY29ubnUgb3UgcsOpaW52ZW50w6nCoC0gZMOpc2lnbsOpIHBhciBsYSB0cmFkaXRpb24uIFBhciBleGVtcGxlLCAqQWxleGFuZHJpIE1hZ25pIGVwaXN0dWxhZSogbmUgZMOpc2lnbmUgcGFzIEFsZXhhbmRlIGxlIEdyYW5kLCBhdXRldXIgZCcqZXBpc3R1bGFlKiwgbWFpcyBkZXMgKmVwaXN0dWxhZSogZG9udCBsJ2F1dGV1ciBlc3QgKkFsZXhhbmRyaSBNYWduaSrCoOKAkyBhdXRyZW1lbnQgZGl0LCBzb3VzIGNldCBpZGVudGlmaWFudCBlc3QgcmVncm91cMOpZSBsYSBjb3JyZXNwb25kYW5jZSBkZSBjZXQgYXV0ZXVyLiBOb3VzIGF2b25zIGNvbnNlcnbDqSBsZXMgbm9tcyB0ZWxzIHF1J2lscyBhcHBhcmFpc3NhaWVudCBkYW5zIGxlcyBkb25uw6llcyBxdWUgbm91cyB1dGlsaXNvbnMuDQoNCiMjIyBQcmluY2lwZXMgbcOpdGhvZG9sb2dpcXVlcw0KDQpOb3VzIGFsbG9ucyBmb3JtYXRlciBsZXMgZG9ubsOpZXMgcXVlIG5vdXMgYXZvbnMgcsOpY3Vww6lyw6llcyBwb3VyIHF1J2VsbGVzIGNvcnJlc3BvbmRlbnQgYXV4IHZhcmlhYmxlcyBxdWUgbm91cyBhdm9ucyBkw6ljcml0ZXMsIGVuIHByb2PDqWRhbnQgc3VjY2Vzc2l2ZW1lbnQgdmFyaWFibGUgcGFyIHZhcmlhYmxlLg0KDQpQb3VyIGNoYXF1ZSBzZWN0aW9uIGRlIGZvcm1hdGFnZSwgbm91cyBhbGxvbnMgcHJvY8OpZGVyIGRhbnMgbCdvcmRyZSBzdWl2YW50wqA6DQoNCi0gKipQcsOpc2VudGF0aW9uKiogZGUgbGEgdmFyaWFibGUgZXQgZHUgZm9ybWF0YWdlIG7DqWNlc3NhaXJlDQotICoqQ3LDqWF0aW9uIGRlIGZvbmN0aW9ucyoqIGFkYXB0w6llcyBwb3VyIGZvcm1hdGVyIGxhIHZhcmlhYmxlIGNvbnZlbmFibGVtZW50DQotICoqVGVzdCoqIGRlcyBmb25jdGlvbnMsIHN1ciBkZXMgZG9ubsOpZXMgY2hvaXNpZXMgb3UgdW5lIGNvcGllIGludGVybcOpZGlhaXJlIGRlIG5vcyBkb25uw6llcw0KLSAqKkFwcGxpY2F0aW9uKiogZGVzIGZvbmN0aW9ucyDDoCBub3MgdGFibGVhdXggZGUgZG9ubsOpZXMNCi0gKipDb3JyZWN0aW9ucyoqIHN1cHBsw6ltZW50YWlyZXMsIHNpIG7DqWNlc3NhaXJlDQotICoqUsOpc3Vtw6kqKiBkZXMgZG9ubsOpZXMgb2J0ZW51ZXMgcG91ciBsYSB2YXJpYWJsZQ0KDQpDZXR0ZSBkw6ltYXJjaGUgbm91cyBwZXJtZXQgZCdhZ2lyLCBkYW5zIGxlIHByb2Nlc3N1cyBkZSBkw6l2ZWxvcHBlbWVudCBkdSBjb2RlIHNvdXJjZSBzZXJ2YW50IMOgIG5vdHJlIGFuYWx5c2UsIGF2ZWMgZmxleGliaWxpdMOpwqA6IG5vdXMgcG91cnJvbnMgbm90YW1tZW50IHLDqWFsaXNlciBkZXMgdGVzdHMgYXUgZnVyIGV0IMOgIG1lc3VyZSBxdWUgbm91cyBhanVzdG9ucyBldCBwZXJmZWN0aW9ubm9ucyBub3MgZm9uY3Rpb25zIGRlIGZvcm1hdGFnZSwgZGFucyB1biBhbGxlci1yZXRvdXIgZW50cmUgc2VjdGlvbiBkZSB0ZXN0cyBldCBzZWN0aW9uIGRlIGNyw6lhdGlvbiBkZSBmb25jdGlvbnMuDQoNCklsIHkgYXVyYSBhaW5zaSBjaW5xIHBhcnRpZXPCoDoNCg0KMS4gW1LDqWN1cMOpcmF0aW9uIGRlIGxhIGxpc3RlIGRlcyBhdXRldXJzIChkZXB1aXMgbGUgZG9ubsOpZXMgUGVyc2V1cyldKCNkZXMtxZN1dnJlcy1hdXgtYXV0ZXVycykNCjIuIFtGb3JtYXRhZ2UgZGVzIGRhdGVzIChyw6ljdXDDqXLDqWVzIMOgIGwnw6l0YXBlIDEpXSgjZm9ybWF0YWdlLWRlcy1kYXRlcykNCjMuIFtGb3JtYXRhZ2UgZGVzIGxpZXV4IChyw6ljdXDDqXLDqXMgw6AgbCfDqXRhcGUgMSldKCNmb3JtYXRhZ2UtZGVzLWxpZXV4KQ0KNC4gW0Fkam9uY3Rpb24gZGVzIGdlbnJlcyBsaXR0w6lyYWlyZXMgKGRlcHVpcyBsZXMgZG9ubsOpZXMgQ0xUSyldKCNhZGpvbmN0aW9uLWRlcy1nZW5yZXMpDQo1LiBbRm9ybWF0YWdlcyBzdXBwbMOpbWVudGFpcmVzIGZpbmF1eF0oI2Zvcm1hdGFnZXMtc3VwcGzDqW1lbnRhaXJlcykNCg0KUG91ciBmaW5pciwgbGEgW3NlY3Rpb24gY29uY2x1c2l2ZV0oI2Rvbm7DqWVzLWZpbmFsZXMtb2J0ZW51ZXMpIGNvbnRpZW5kcmEgbCdlbnNlbWJsZSBkZXMgZG9ubsOpZXMgYWluc2kgb2J0ZW51ZXMuDQoNCiMjIyAxLjEuIERlcyDFk3V2cmVzIGF1eCBhdXRldXJzDQoNClB1aXNxdWUgbGVzIGRvbm7DqWVzIHLDqWN1cMOpcsOpZXMgZGVwdWlzIGxlIHRhYmxldXIgZHUgcHJvamV0IFBlcnNldXMgY29uc2lzdGVudCBlbiB1bmUgbGlzdGUgZCfFk3V2cmVzLCBub3VzIGRldm9ucyBlbiBmYWlyZSB1bmUgbGlzdGUgZCdhdXRldXJzLCBlbiByw6ljdXDDqXJhbnQgbGVzIGRvbm7DqWVzIHF1aSBub3VzIGludMOpcmVzc2VudC4NCg0KT24gY29uc2VydmUsIHBvdXIgY2hhcXVlIGF1dGV1ciwgbGVzIHZhcmlhYmxlcyBzdWl2YW50ZXPCoDoNCg0KRGVzY3JpcHRpb24gfCBOb20gZGFucyBub3RyZSB0YWJsZWF1IHwgTm9tIGRhbnMgbGUgdGFibGVhdSBvcmlnaW5hbA0KLS0tIHwgLS0tIHwgLS0tDQpub20gfCBgbmFtZWAgfCBgVExHYCAvIGBQSElgIGBBVVRIT1IgTkFNRWANCmlkZW50aWZpYW50IHwgYGNvZGVgIHwgYFRMR2AgLyBgUEhJYCBgI2ANCmxpZXUgfCBgcGxhY2VgIHwgYExvY2F0aW9uYA0KZGF0ZSBkJ2FjdGl2aXTDqSB8IGBkYXRlX2FjdGl2ZWAgfCBgQ2VudHVyeS9EYXRlcyBBY3RpdmVgDQpkYXRlICJkZSBkw6lwYXJ0IiBvdSBkZSBuYWlzc2FuY2UgfCBgZGF0ZV9iZWdpbmAgfCBgQmVnaW4gRGF0ZS9CaXJ0aCBZZWFyYA0KZGF0ZSAiZGUgZmluIiBvdSBkZSBtb3J0IHwgYGRhdGVfZW5kYCB8IGBFbmQgRGF0ZS9EZWF0aCBZZWFyYA0KDQpQb3VyIGxhIGRhdGUgZCdhY3Rpdml0w6ksIGlsIHMnYWdpdCBsZSBwbHVzIHNvdXZlbnQgZGUgc2nDqGNsZXMsIGZvcm1hdMOpcyBjb21tZSBkZXMgYW5uw6llcyBtdWx0aXBsZXMgZGUgMTAwICgqZWcuICIxMDAgQ0UiIGNvcnJlc3BvbmQgYXUgcHJlbWllciBzacOoY2xlKikuIFBvdXIgbGVzIGRhdGVzIGRlIGTDqWJ1dCBvdSBkZSBmaW4sIGlsIHMnYWdpdCBkJ2FubsOpZXMgb3UgZGUgc2nDqGNsZXMgKGZvcm1hdMOpcyBhbG9ycyBjb21tZSBwcsOpY8OpZGVtbWVudCkuDQoNCmBgYHtyIGZyb20td29ya3MtaW50cm99DQojIFdlIHdpbGwgY29tcHV0ZSB0aGUgYXV0aG9ycyBkYXRhZnJhbWVzIGZyb20gdGhlIHdvcmtzIGRhdGFmcmFtZXMuDQpgYGANCg0KYGBge3IgZnJvbS13b3Jrcy1kZW1vLCBldmFsID0gRkFMU0V9DQojIERpZGFjdGljIGRlbW8gY29kZTogc2VsZWN0aW5nIGFuZCByZW5hbWluZyBjb2x1bW5zLg0KdGxnX2F1dGhvcnNfZGYgPC0NCiAgdGxnX3dvcmtzX3Jhd19kZiAlPiUNCiAgdHJhbnNtdXRlKA0KICAgIGNvZGUgPSBgVExHI2AsDQogICAgbmFtZSA9IGBUTEcgQVVUSE9SIE5BTUVgLA0KICAgIHBsYWNlID0gYExvY2F0aW9uYCwNCiAgICBkYXRlX2FjdGl2ZSA9IGBDZW50dXJ5L0RhdGVzIEFjdGl2ZWAsDQogICAgZGF0ZV9iZWdpbiA9IGBCZWdpbiBEYXRlL0JpcnRoIFllYXJgLA0KICAgIGRhdGVfZW5kID0gYEVuZCBEYXRlL0RlYXRoIFllYXJgDQogICkNCmBgYA0KDQojIyMjIEZvbmN0aW9ucyBldCBhcHBsaWNhdGlvbg0KDQpgYGB7ciBub3Rlcy1vbi1mdW5jdGlvbnN9DQojIFNpbmNlIHdlIHdpbGwgYmUgZG9pbmcgZXhhY3RseSB0aGUgc2FtZSBvcGVyYXRpb25zIG9uIGJvdGggd29ya3MgbGlzdCwNCiMgd2Ugd2lsbCB1c2UgZnVuY3Rpb25zICh0byBhdm9pZCBodXJ0ZnVsIGNvcHktcGFzdGluZywgd2hpY2ggaXMgaW5jb252ZW5pZW50IGZvciBjb2RlIG1vZGlmaWNhdGlvbnMpLg0KIyBIb3BlZnVsbHksIGNvbHVtbiBuYW1lcyBhcmUgYWxtb3N0IHRoZSBzYW1lIGluIGJvdGggcmV0cmlldmVkIGRvY3VtZW50cy4NCmBgYA0KDQpgYGB7ciBmcm9tLXdvcmtzLWFwcGx5fQ0KIyBQYXNzaW5nIGNvbHVtbiBuYW1lcyB0aHJvdWdoIGEgZnVuY3Rpb24gaXMgbm90IG9idmlvdXMsDQojIGJ1dCBpdCdzIHBvc3NpYmxlIGlmIHdlIHVzZSB3aGF0IGlzIGNhbGxlZCBxdW9zdXJlcy4NCiMgQHNlZSBodHRwczovL2dpdGh1Yi5jb20vci1saWIvcmxhbmcvaXNzdWVzLzExNg0KIyBAc2VlIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQ4MDYyMjEzL2RwbHlyLXVzaW5nLWNvbHVtbi1uYW1lcy1hcy1mdW5jdGlvbi1hcmd1bWVudHMNCg0KIycgRXh0cmFjdCBhdXRob3JzIGZyb20gcmF3IHdvcmtzIGRhdGFmcmFtZS4NCiMnIEBwYXJhbSB3b3Jrc19yYXdfZGYgRGF0YWZyYW1lLiBXb3JrcyBhcyBkYXRhZnJhbWUsIGV4dHJhY3RlZCBmcm9tIGRhdGEuDQojJyBAcGFyYW0gc3BlY2lmaWNfZmlsbGluZyBTdHJpbmcuIFN0cmluZyB0aGF0IGlzIHNwZWNpZmljIHRvIHRoZSBjb2x1bW5zIG5hbWVzIGluIHRoZSBkYXRhLg0KIycgZS5nLiAiUEhJIiBpcyB1c2VkIGluIHRoZSBsYXRpbiB3b3JrcyBkYXRhZnJhbWUgZm9yIG5hbWluZyBzb21lIGNvbHVtbnMsDQojJyB3aGVyZWFzICJUTEciIGlzIHByZWZlcmVkIGluIHRoZSBncmVlayBvbmUuDQojJyBAcmV0dXJuIERhdGFmcmFtZS4gQXV0aG9ycyBhcyBkYXRhZnJhbWUuDQpleHRyYWN0X2F1dGhvcnMgPC0gZnVuY3Rpb24od29ya3NfcmF3X2RmLCBzcGVjaWZpY19maWxsaW5nKSB7DQogICMgQ29tcHV0ZSBzb21lIGNvbHVtbiBuYW1lcyB0aGF0IGFyZSBzcGVjaWZpYyB0byB0aGUgZ2l2ZW4gZGF0YSBmcmFtZS4NCiAgY29kZV9jb2xfbmFtZSA8LSBwYXN0ZTAoc3BlY2lmaWNfZmlsbGluZywiIyIpDQogIGF1dGhvcl9jb2xfbmFtZSA8LSBwYXN0ZTAoc3BlY2lmaWNfZmlsbGluZywiIEFVVEhPUiBOQU1FIikNCg0KICAjIEJ1aWxkIHRoZSBkYXRhIGZyYW1lLg0KICBhdXRob3JzX2RmIDwtDQogICAgIyAxLiBLZWVwIG9ubHkgdGhlIGNvbHVtbnMgd2UgbmVlZCBmcm9tIHJhdyBkYXRhIGFuZCByZW5hbWUgdGhlbS4NCiAgICB3b3Jrc19yYXdfZGYgJT4lDQogICAgdHJhbnNtdXRlKA0KICAgICAgY29kZSA9ICEhc3ltKGNvZGVfY29sX25hbWUpLCAgICAjIElkZW50aWZpYW50IGRlIGwnYXV0ZXVyDQogICAgICBuYW1lID0gISFzeW0oYXV0aG9yX2NvbF9uYW1lKSwgICMgTm9tIGRlIGwnYXV0ZXVyDQogICAgICBwbGFjZSA9IGBMb2NhdGlvbmAsDQogICAgICBkYXRlX2FjdGl2ZSA9IGBDZW50dXJ5L0RhdGVzIEFjdGl2ZWAsDQogICAgICBkYXRlX2JlZ2luID0gYEJlZ2luIERhdGUvQmlydGggWWVhcmAsDQogICAgICBkYXRlX2VuZCA9IGBFbmQgRGF0ZS9EZWF0aCBZZWFyYA0KICAgICkgJT4lDQogICAgIyAyLiBEcm9wIHRyYWlsaW5nIGNhcnJpYWdlIHJldHVybnMgdGhhdCBtZXNzIHRoaW5ncyB1cC4NCiAgICBtdXRhdGVfYWxsKH4gc3RyX3JlcGxhY2VfYWxsKC4sICJcbiQiLCAiIikpICU+JQ0KICAgICMgMy4gVHJpbSBhbGwuDQogICAgbXV0YXRlX2FsbCh+IHN0cl90cmltKC4pKSAlPiUNCiAgICAjIDQuIEtlZXAgb25seSB0aGUgZmlyc3QgZm91ciBkaWdpdHMgZnJvbSB0aGUgY29kZSwNCiAgICAjIGFuZCBwYXJzZSBpdCB0byBhIG51bWVyaWNhbCB2YWx1ZSBmb3IgZnVydGhlciBhbmFseXNpcy4NCiAgICAjIE9ubHkgdGhlIGZpcnN0IGZvdXIgYXJlIHJlbGV2YW50IHRvIHRoZSBhdXRob3IsDQogICAgIyBvdGhlciB0cmFpbGluZyBjaGFyYWN0ZXJzIGluIHRoZSBjb2RlDQogICAgIyBjYW4gY2hhcmFjdGVyaXplIHRoZSB3b3JrLCBmb3IgaW5zdGFuY2UNCiAgICAjIChyZW1lbWJlciBpdCdzIGEgbGlzdCBvZiB3b3JrcyB3ZSBoYXZlIGF0IHRoZSBiZWdpbm5pbmcpLg0KICAgICMgQmV3YXJlOiBXaGVuIG51bWJlcnMgYXJlIDwxMDAwLCB0aGV5IGFyZSBub3QgYWx3YXlzIHBhZGRlZCBvbiB0aGUgcmlnaHQuDQogICAgbXV0YXRlKA0KICAgICAgY29kZSA9IGNvZGUgJT4lDQogICAgICAgIHN0cl9leHRyYWN0KCJeXFxkezEsNH0iKSAlPiUNCiAgICAgICAgcGFyc2VfbnVtYmVyKCkNCiAgICApICU+JQ0KICAgICMgNS4gU2VsZWN0IG9ubHkgb25lIHJvdyBwZXIgdW5pcXVlIGNvZGUsDQogICAgIyB0aGF0IGlzIHRvIHNheToga2VlcCBvbmx5IG9uZSByb3cgcGVyIGF1dGhvciwNCiAgICAjIGluc3RlYWQgb2Ygb25lIHJvdyBwZXIgd29yay4NCiAgICAjIFdlIGNvdWxkIGhhdmUgdXNlZCB0aGUgYXV0aG9yJ3MgbmFtZSwgYnV0DQogICAgIyAxKSB1c2luZyB0aGUgY29kZSBkcm9wcyB0aGUgYXV0aG9ycyB3aG8gZG8gbm90IGhhdmUgYSBjb2RlLA0KICAgICMgYW5kIHNpbmNlIHdlIHdhbnQgdG8gYW5hbHl6ZSBjb2RlcywNCiAgICAjIHdlIGhhdmUgbm8gdXNlIG9mIGF1dGhvcnMgdGhhdCBkbyBub3QgaGF2ZSBhIGNvZGU7DQogICAgIyAyKSB1c2luZyB0aGUgbmFtZSB3b3VsZCBrZWVwIG9ubHkgb25lIGluZGl2aWR1YWwgZm9yIGhvbm9ueW1zIGluc3RlYWQgb2Ygc2V2ZXJhbC4NCiAgICAjIHJxOiBJdCBrZWVwcyBvbmUgcm93IHdpdGggJ05BJyBhcyBjb2RlLCB3ZSB3aWxsIHJlbW92ZSBpdCBoZXJlYWZ0ZXIuDQogICAgZGlzdGluY3QoY29kZSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lDQogICAgIyA2LiBTb3J0IGJ5IGNvZGUuDQogICAgYXJyYW5nZShjb2RlKSAlPiUNCiAgICAjIDcuIFJlcGxhY2UgTkEtZXF1aXZhbGVudCB2YWx1ZXMgdG8gcHJvcGVyIE5BLg0KICAgIG11dGF0ZV9hbGwofiByZXBsYWNlKC4sIC4gJWluJSBuYV92YXJpYW50cywgTkEpKSAlPiUNCiAgICAjIDguIERyb3Agcm93cyB0aGF0IGRvbid0IGhhdmUgYW55IGNvZGUuDQogICAgZHJvcF9uYShjb2RlKQ0KDQogICMgUmV0dXJuIHRoZSBkYXRhIGZyYW1lLg0KICByZXR1cm4oYXV0aG9yc19kZikNCn0NCg0KcGhpX2F1dGhvcnNfZGYgPC0gZXh0cmFjdF9hdXRob3JzKHBoaV93b3Jrc19yYXdfZGYsICJQSEkiKQ0KdGxnX2F1dGhvcnNfZGYgPC0gZXh0cmFjdF9hdXRob3JzKHRsZ193b3Jrc19yYXdfZGYsICJUTEciKQ0KYGBgDQoNCiMjIyMgQ29ycmVjdGlvbnMgZCdlcnJldXJzIG1hbnVlbGxlcw0KDQpOb3VzIG4nYXZvbnMgcGFzIHbDqXJpZmnDqSBkZSBtYW5pw6hyZSBzeXN0w6ltYXRpcXVlIGxlcyBlcnJldXJzIHF1aSBwZXV2ZW50IMOqdHJlIHByw6lzZW50ZXMgZGFucyBsZXMgZG9ubsOpZXMgcXVlIG5vdXMgYXZvbnMgcsOpY3Vww6lyw6llcywgbm91cyBjb3JyaWdlb25zIHNldWxlbWVudCBjZWxsZXMgcXVpIHJlbMOodmVudCBkZSB2YWxldXJzIGFiZXJyYW50ZXMgaW1tw6lkaWF0ZW1lbnQgdmlzaWJsZXMgbG9ycyBkZSBub3MgZm9ybWF0YWdlcyB1bHTDqXJpZXVycywgbWFuaWZlc3RlbWVudCBkdWVzIMOgIGRlcyBlcnJldXJzIGRlIGZyYXBwZSwgY29tbWUgcGFyIGV4ZW1wbGUgbCdpbmRpY2F0aW9uIGRlICJSaG9kZXMiIGNvbW1lIHNpw6hjbGUgZCdhY3Rpdml0w6kuDQoNCmBgYHtyIGF1dGhvcnMtY29ycmVjdGlvbnN9DQojIFNvbWUgbWFudWFsIGNvcnJlY3Rpb25zIG9mIGVycm9ycyBpbiB0aGUgZGF0YS4NCiMgVGhlIHRyYW5zZm9ybWF0aW9ucyBhcmUgYXMgZm9sbG93czoNCiMgLSBwbGFjZSA8LT4gZGF0ZV9hY3RpdmUsIGZvciAyMzUzIChpbnN0ZWFkIG9mICI1MDAgQkNFIiBhcyBwbGFjZSBhbmQgIlJob2RlcyIgYXMgZGF0ZSkNCiMgLSBwbGFjZSAtPiBkYXRlX2FjdGl2ZSwgZm9yIDE3ODQgKGluc3RlYWQgb2YgIjQwMCBCQ0UiIGFzIHBsYWNlKQ0KIyAtIGRhdGVfYWN0aXZlIC0+IE5BLCBmb3IgMjUxNCAoaW5zdGVhZCBvZiAiUm9tZSwgSXRhbHkiKQ0KIyAtIGRhdGVfZW5kIC0+ICI0OTUgQkNFLzQ3OCBCQ0UiLCBmb3IgMDIzNyAoaW5zdGVhZCBvZiAiQ0UiIHdoZW4gdGhlIG90aGVyIHR3byBhcmUgIkJDRSIpDQp0bXBfcGxhY2VfMjM1MyA8LQ0KICB0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKGNvZGUgPT0gMjM1MykgJT4lDQogIHB1bGwoZGF0ZV9hY3RpdmUpDQp0bGdfYXV0aG9yc19kZiA8LSB0bGdfYXV0aG9yc19kZiAlPiUNCiAgbXV0YXRlKA0KICAgIGRhdGVfYWN0aXZlID0gY2FzZV93aGVuKA0KICAgICAgY29kZSA9PSAxNzg0IHwgY29kZSA9PSAyMzUzIH4gcGxhY2UsDQogICAgICBjb2RlID09IDI1MTQgfiBOQV9jaGFyYWN0ZXJfLA0KICAgICAgVFJVRSB+IGRhdGVfYWN0aXZlDQogICAgKSwNCiAgICBwbGFjZSA9IGNhc2Vfd2hlbigNCiAgICAgIGNvZGUgPT0gMTc4NCB+IE5BX2NoYXJhY3Rlcl8sDQogICAgICBjb2RlID09IDIzNTMgfiB0bXBfcGxhY2VfMjM1MywNCiAgICAgIFRSVUUgfiBwbGFjZQ0KICAgICksDQogICAgZGF0ZV9lbmQgPSBjYXNlX3doZW4oDQogICAgICBjb2RlID09IDIzNyB+ICI0OTUgQkNFLzQ3OCBCQ0UiLA0KICAgICAgVFJVRSB+IGRhdGVfZW5kDQogICAgKQ0KICApDQojIFJlbW92ZSB2YXJpYWJsZXMgdGhhdCBhcmUgdXNlbGVzcyBpbiB0aGUgZnV0dXJlLg0KcmVtb3ZlKHRtcF9wbGFjZV8yMzUzKQ0KYGBgDQoNCiMjIyAxLjIuIEZvcm1hdGFnZSBkZXMgZGF0ZXMNCg0KTGVzIGRhdGVzIGV4dHJhaXRlcyBkZSBub3MgZG9ubsOpZXMgZCdvcmlnaW5lIHNvbnQgcGV1IG1vYmlsaXNhYmxlcyBkYW5zIGRlcyBhbmFseXNlcyBzdGF0aXN0aXF1ZXMsIGVsbGVzIG1hbnF1ZW50IGRlIGNvaMOpcmVuY2UgZXQgc29udCBkaWZmaWNpbGVtZW50IGludGVycHLDqXRhYmxlcyBwcm9ncmFtbWF0aXF1ZW1lbnQsIG5lIGNvcnJlc3BvbmRhbnQgw6AgYXVjdW4gZm9ybWF0IHN0cnVjdHVyw6kuDQoNCk5vdXMgYWxsb25zIGRvbmMgbGVzIGZvcm1hdGVyIGNvbnZlbmFibGVtZW50Lg0KDQpMZXMgZG9ubsOpZXMgZCdvcmlnaW5lIHNvbnQgdGV4dHVlbGxlcyBldCBjb250aWVubmVudCBwbHVzaWV1cnMgZXJyZXVycyBldCBpcnLDqWd1bGFyaXTDqXMuIFBhciBjb25zw6lxdWVudCwgbGUgdHJhdmFpbCBkJ2VuY29kYWdlIMOgIGZhaXJlIGVzdCBpbXBvcnRhbnQuDQoNCk5vdXMgYWxsb25zIGNvbW1lbmNlciBwYXIgw6l0YWJsaXIgbGVzIGV4cHJlc3Npb25zIHLDqWd1bGnDqHJlc8KgOiBkJ2Fib3JkIGNlbGxlcyBxdWkgc2VtYmxlbnQgY29ycmVzcG9uZHJlIHBsdXMgb3UgbW9pbnMgYXV4IGRvbm7DqWVzIGRlIGTDqXBhcnQsIHB1aXMgY2VsbGVzIGF1eHF1ZWxsZXMgbm91cyBzb3VoYWl0b25zIGZhaXJlIHN0cmljdGVtZW50IGNvcnJlc3BvbmRyZSBsZXMgZG9ubsOpZXMgIm1pc2VzIGF1IHByb3ByZSIuDQoNClVuZSBmb2lzIGNldCBvYmplY3RpZiBkw6l0ZXJtaW7DqSwgbm91cyBkZXZyb25zIHRvdXQgZCdhYm9yZCByZS1mb3JtYXRlciBsZXMgZGF0ZXMgZW4gcmVzdGFudCBkYW5zIGxlIGRvbWFpbmUgZGVzIGNoYcOubmVzIGRlIGNhcmFjdMOocmVzLCBkZSB0ZWxsZSBzb3J0ZSBxdSdlbGxlcyBjb3JyZXNwb25kZW50IHNjcnVwdWxldXNlbWVudCDDoCBsJ2V4cHJlc3Npb24gcsOpZ3VsacOocmUgZmluYWxlIHF1ZSBub3VzIHNvdWhhaXRvbnMsIHB1aXMsIHVuZSBmb2lzIGNlIHRyYXZhaWwgYWNjb21wbGksIG5vdXMgcG91cnJvbnMgbGVzIGNvbnZlcnRpciBlbiBub21icmUgZmFjaWxlbWVudC4NCg0KTCdleHByZXNzaW9uIHLDqWd1bGnDqHJlIGZpbmFsZSBhdXJhIGxhIGZvcm1lIHN1aXZhbnRlwqA6DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQoiKGFudGV8cG9zdCk/KFxcZHsxLDR9KShjZXxiY2UpKFxcPyk/Ig0KYGBgDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO21hcmdpbi10b3A6MjBweDtmb250LXNpemU6bGFyZ2VyIj4NCiAgPHNwYW4gc3R5bGU9ImNvbG9yOiMzNDk4ZGIiPmFudGU8L3NwYW4+DQogIDxzcGFuIHN0eWxlPSJjb2xvcjojZTc0YzNjIj4yMDA8L3NwYW4+DQogIDxzcGFuIHN0eWxlPSJjb2xvcjojOWI1OWI2Ij5iY2U8L3NwYW4+DQogIDxzcGFuIHN0eWxlPSJjb2xvcjojMjhiNDYzIj4/PC9zcGFuPg0KPC9kaXY+DQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO21hcmdpbi1ib3R0b206MjBweDtmb250LXNpemU6c21hbGxlciI+DQogIDxzcGFuIHN0eWxlPSJjb2xvcjojMzQ5OGRiIj5hdmFudCAvIGFwcsOocyBsYSBkYXRlIGNvbnNpZMOpcsOpZTwvc3Bhbj48YnI+DQogIDxzcGFuIHN0eWxlPSJjb2xvcjojZTc0YzNjIj5hbm7DqWU8L3NwYW4+PGJyPg0KICA8c3BhbiBzdHlsZT0iY29sb3I6IzliNTliNiI+YXZhbnQgLyBkZSBub3RyZSDDqHJlPC9zcGFuPjxicj4NCiAgPHNwYW4gc3R5bGU9ImNvbG9yOiMyOGI0NjMiPmluZGljYXRldXIgZGUgZGF0ZSBpbmNlcnRhaW5lPC9zcGFuPjxicj4NCjwvZGl2Pg0KDQpMYSBkYXRlIHBldXQgw6lnYWxlbWVudCDDqnRyZSB1biBpbnRlcnZhbGxlwqA6IGNlIHNvbnQgYWxvcnMgZGV1eCBkYXRlcyBmb3JtYXTDqWVzIGNvbW1lIGNpLWRlc3N1cyBsacOpZXMgcGFyIHVuIHRpcmV0Lg0KDQpOb3VzIG5lIHJldGllbmRyb25zIG7DqWFubW9pbnMgc291cyBsYSBmb3JtZSBudW3DqXJpcXVlLCBwb3VyIGNoYXF1ZSBkYXRlLCBxdWUgbGVzIGRldXggcGFydGllcyBjZW50cmFsZXMsIMOgIHNhdm9pciBsJ2FubsOpZSBldCBzaSBjZWxhIGVzdCBhdmFudCBub3RyZSDDqHJlIG91IGRlIG5vdHJlIMOocmUuICJgYW50ZTIwMGJjZT9gIiBkb25uZXJhIGRvbmMgImAtMjAwYCIuDQoNCkNvbW1lIG5vdXMgbCdhdm9ucyBkw6lqw6Agw6l2b3F1w6ksIGxvcnNxdWUgbm91cyBzZXJvbnQgZmFjZSDDoCB1biBpbnRlcnZhbGxlLCBub3VzIHByZW5kcm9ucyBsYSBtb3llbm5lIGRlcyBleHRyw6ltaXTDqXPCoDogImAxMDBjZS0yMDBjZWAiIGRvbm5lICJgMTUwYCIuDQoNCiMjIyMgUmVtYXJxdWVzIHRlY2huaXF1ZXMgaW50cm9kdWN0aXZlcw0KDQpgYGB7ciBkYXRlLWludHJvfQ0KIyBXZSB3aWxsIG5lZWQgYSBkYXRlIHBhcnNlci4NCg0KIyBXZSBjb3VsZCBleHRyYWN0IHRoZSBmaXJzdCAobW9zdC1sZWZ0KSBtYXRjaCBmcm9tIHRoZSBzZXF1ZW5jZSBvZiBkaWdpdHMsDQojIHdoaWNoIHdvdWxkIGJlIGdvb2QgZW5vdWdoLA0KIyBidXQgdGhpcyBkb2VzIG5vdCBkZWFsIHdpdGggQkNFL0NFLCBub3IgZG9lcyBpdCBhc3N1cmUgZGF0YSBjb3JyZWN0bmVzcy4NCiMgU28gd2Ugd2lsbCBwYXJzZSB0aGluZ3MgaW4gYSBuZWF0bGllciB3YXkuDQpgYGANCg0KYGBge3IgZGF0ZS1ub3RlcywgZXZhbCA9IEZBTFNFfQ0KIyBIZXJlIHdlIGhhdmUgdG8gZGVhbCB3aXRoIHRoZSBkYXRlIGJlZm9yZSBjb21tb24gZXJhIChCQ0UpIGFuZCB3aXRoaW4gY29tbW9uIGVyYSAoQ0UpLg0KDQojIFRoaXMgY2F1c2VzIGEgZmV3IHByb2JsZW1zDQojIHNpbmNlIG1vc3Qgc3BlY2lmaWNhdGlvbnMgYW5kIHBhY2thZ2VzIGRvIG5vdCBkZWFsIHdpdGggdGhpcyBuYXRpdmVseToNCg0KIyAtIFRpbWVzdGFtcHMgdXN1YWxseSBzdGFydCBhdCAxOTcwLTAxLTAxLg0KIyBEYXRlcyBiZWZvcmUgYXJlIHN0b3JlZCBhcyBuZWdhdGl2ZSB2YWx1ZXMsIGVnLg0KbHVicmlkYXRlOjp5bWRfaG1zKCIxOTY5LTEyLTMxVDIzOjU5OjU5IikgIyA9PSAtMQ0KDQojIC0gSVNPIDg2MDEgeWVhciBzdGFydHMgYXQgMDAwMC0wMS0wMSB3aGljaCBpcyB0aGUgMXN0IEphbnVhcnkgb2YgMSBCQ0UuDQojIEBzZWUgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSVNPXzg2MDENCg0KIyBSZW1pbmRlcjogVGhlcmUgaXMgbm8gc3VjaCB0aGluZyBhcyB5ZWFyIHplcm8uDQojIEBzZWUgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvWWVhcl96ZXJvDQojIEFsdGhvdWdoLCB0aGVyZSBhcmUgc29tZSAiMCBDRSIgYW5kICIwIEJDRSIgaW4gb3VyIGRhdGEsIHdoaWNoIGlzIG5vdCBjbGVhci4NCmBgYA0KDQpgYGB7ciBkYXRlLW5vdGVzLWx1YnJpZGF0ZSwgZXZhbCA9IEZBTFNFfQ0KIyBBIGZldyByZW1hcmtzIGFib3V0IHRoZSBsdWJyaWRhdGUgcGFja2FnZS4NCg0KIyBUaGUgbHVicmlkYXRlIHBhY2thZ2UNCiMgLSBEb2VzIG5vdCBoYW5kbGUgQkNFIGRhdGUgbmF0aXZlbHkNCiMgLSBXaWxsIG5vdCBiZSBhYmxlIHRvIG1hdGNoIG91ciBkYXRhIGFzIHJhdyB2YWx1ZXMNCiMgKHRoYXQgaGF2ZSBpbnRlcnZhbHMgYW5kIENFL0JDRSBzcGVjaWZpY2F0aW9ucykNCiMgQHNlZSBodHRwczovL2x1YnJpZGF0ZS50aWR5dmVyc2Uub3JnLw0KIyBAc2VlIGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL21hc3Rlci9sdWJyaWRhdGUucGRmDQojIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3RpZHl2ZXJzZS9sdWJyaWRhdGUvaXNzdWVzLzINCg0KIyBJZiB3ZSB3YW50IHRvIGRlYWwgd2l0aCBCQ0UgZGF0ZSBhbnl3YXksIHdlIGNvdWxkIGRvIHNvbWV0aGluZyBzdWNoIGFzOg0KbHVicmlkYXRlOjp5bWQoIjAwMDAtMDEtMDEiKSAtIGx1YnJpZGF0ZTo6eWVhcnMoMSkgIyA9PSAiLTAwMS0wMS0wMSINCiMgQFdBUk46IFNpbmNlICIwMDAwLTAxLTAxIiBpcyAxIEJDRSwgIi0wMDAxLTAxLTAxIiB3b3VsZCBiZSAyIEJDRS4NCiMgV2UgY291bGQgd3JpdGUgYSBoZWxwZXIgZnVuY3Rpb24gdG8gcmV0cmlldmUgY29ycmVjdCBkYXRlcyBmcm9tIHRoaXMsDQojIGFsc28gdGFraW5nIGludG8gYWNjb3VudCBtb250aHMsIGRheXMsIGV0Yy4sIHRoYXQgd2UgZG8gbm90IG5lZWQgaGVyZS4NCmBgYA0KDQpPbiBwcsOpcGFyZSBsZXMgZG9ubsOpZXMgcXVpIG5vdXMgc2Vydmlyb250IHBvdXIgbm9zIHRlc3RzLg0KDQpgYGB7ciBkYXRlLXRlc3Qtc2FtcGxlLCBldmFsID0gRkFMU0V9DQojIFRlc3Qgc2FtcGxlIGZyb20gdGhlIGRhdGEsDQojIHRvIGJ1aWxkIHJlZ2V4IGZpdHRlZCBmb3IgbW9zdCBjb21tb24gY2FzZXMuDQp0ZXN0X2RhdGVzIDwtIGMoDQogICI0MDAgQkNFIiwNCiAgIjIwMCBCQ0U/IiwNCiAgIjEwIENFIiwNCiAgIjAxIENFIiwNCiAgIjIwMCBDRSIsDQogICIyMDAgQ0U/IiwNCiAgIjEwNTAgQ0UiLA0KICAiYW50ZSAyMDAgQ0UiLA0KICAiQW50ZSAxMDAgQ0UiLA0KICAicG9zdCAyMDAgQ0UiLA0KICAiOTAgQ0UvOTUgQ0UiLA0KICAiMTAwIEJDRS0wIENFIiwNCiAgIjYwMCBCQ0UtNTAwIEJDRSIsDQogICIxMDAgQ0UtMjAwIENFPyIsDQogICIxMDAgQkNFLTEwMCBDRSIsDQogICIyODQgQkNFLzI3NSBCQ0UiLA0KICAiMTEwMCBDRS0xMjAwIENFIiwNCiAgImFudGUgMTAwIENFLTIwMCBDRSIsDQogICMgV3JpdGluZyBlcnJvcnM/DQogICI1MDAgQkNFLSIsDQogICIyMDAgLSA0MDAgQ0UiDQopDQoNCiMgRXZlcnkgZGF0ZSBpbiB0aGUgZGF0YSwgdG8gZnVuY3Rpb25zIGFnYWluc3QgdGhlbS4NCnRlc3RfY29sc19kYXRlcyA8LSBjKA0KICB0bGdfYXV0aG9yc19kZiRkYXRlX2FjdGl2ZSwNCiAgdGxnX2F1dGhvcnNfZGYkZGF0ZV9iZWdpbiwNCiAgdGxnX2F1dGhvcnNfZGYkZGF0ZV9lbmQsDQogIHBoaV9hdXRob3JzX2RmJGRhdGVfYWN0aXZlLA0KICBwaGlfYXV0aG9yc19kZiRkYXRlX2JlZ2luLA0KICBwaGlfYXV0aG9yc19kZiRkYXRlX2VuZA0KKQ0KYGBgDQoNCiMjIyMgVHJvdXZlciBsJ2V4cHJlc3Npb24gcsOpZ3VsacOocmUgYWRhcHTDqWUNCg0KYGBge3IgZGF0ZS1yZWdleH0NCiMgUmVndWxhciBleHByZXNzaW9ucy4NCiMgcnE6IFRoZSAoP2kpIGZsYWcgZm9yIGNhc2UtaW5zZW5zaXRpdml0eSB3b3JrcyB3aXRoIHRoZSBzdHJpbmdyIHBhY2thZ2UuDQojIEl0IG1heSBlbmQgdXAgZHVwbGljYXRlZCBoZXJlLCBidXQgaXQgZG9lcyBub3Qgc2VlbSB0byBtYXR0ZXIuDQoNCiMgMS4gTG9vc2UgcmVndWxhciBleHByZXNzaW9ucywNCiMgYXZvaWRpbmcgYW55IHJlLXdyaXRpbmcgb2YgZGF0YS4NCmRhdGVfbG9vc2Vfc2luZ2xlX3JlZ2V4IDwtICIoP2kpKChhbnRlfHBvc3R8cHJlfGJlZm9yZSk/ID9cXGR7MSw0fSA/KENFfEJDRSlcXD8/LT8pIg0KZGF0ZV9sb29zZV9yZWdleCA8LSBwYXN0ZTAoZGF0ZV9sb29zZV9zaW5nbGVfcmVnZXgsIiA/KCgtfC8pID8iLGRhdGVfbG9vc2Vfc2luZ2xlX3JlZ2V4LCIpPyIpDQoNCiMgMi4gU3RyaWN0IHJlZ3VsYXIgZXhwcmVzc2lvbnMsDQojIHRoYXQgcmVxdWlyZXMgcHJlLWZvcm1hdHRpbmcgb2YgZGF0YSwNCiMgc3VjaCBhcyB3aGl0ZXNwYWNlcyByZW1vdmluZyBhbmQgdGVybXMgaG9tb2dlbmVpdHkuDQpkYXRlX3NpbmdsZV9yZWdleCA8LSAiKGFudGV8cG9zdCk/KFxcZHsxLDR9KShjZXxiY2UpKFxcPyk/Ig0KIyBDYXB0dXJpbmcgZ3JvdXBzIChzdGFydGluZyBhdCAyLCBpbiBjb2x1bW5zIG9mIHRoZSBtYXRyaXggcmVzdWx0aW5nIGZyb21gbWF0Y2goKWApOg0KIyAtIDItNSBhcmUgZm9yIGxlZnQtc2lkZSAoc3RhcnQgb2YgZGF0ZSBpbnRlcnZhbCkNCiMgLSA2LTkgYXJlIGZvciByaWdodC1zaWRlIChlbmQgb2YgZGF0ZSBpbnRlcnZhbCkNCiMgLSAyLCA2OiAiYW50ZSIgb3IgInBvc3QiIChvcHRpb25hbCkNCiMgLSAzLCA3OiB5ZWFyIGFzIG51bWJlcg0KIyAtIDQsIDg6ICJjZSIgb3IgImJjZSINCiMgLSA1LCA5OiB3aGV0aGVyIGl0IGlzIGFuIGFwcHJveGltYXRpb24gKG9wdGlvbmFsKQ0KZGF0ZV9yZWdleCA8LSBwYXN0ZTAoZGF0ZV9zaW5nbGVfcmVnZXgsIig/Oi0iLGRhdGVfc2luZ2xlX3JlZ2V4LCIpPyIpDQpgYGANCg0KYGBge3IgZGF0ZS1yZWdleC10ZXN0LCBldmFsID0gRkFMU0V9DQojIFRlc3QgdG8gYWRqdXN0IHJlZ2V4IGdyYWR1YWxseSwgd2UgbG9vayBhdCB3aGF0IGRvZXMgbm90IHBhc3MgdGhlIHJlZ2V4Lg0KdGVzdF9kYXRlcyAlPiUgc3RyX3N1YnNldChwYXN0ZTAoIl4iLGRhdGVfbG9vc2VfcmVnZXgsIiQiKSwgbmVnYXRlID0gVFJVRSkNCnRlc3RfY29sc19kYXRlcyAlPiUNCiAgc2V0ZGlmZihuYV92YXJpYW50cykgJT4lDQogIHN0cl9zdWJzZXQocGFzdGUwKCJeIixkYXRlX2xvb3NlX3JlZ2V4LCIkIiksIG5lZ2F0ZSA9IFRSVUUpDQpgYGANCg0KQXByw6hzIHBsdXNpZXVycyBlc3NhaXMsIG9uIGNvbXByZW5kIHF1J3VuZSBleHByZXNzaW9uIHLDqWd1bGnDqHJlIG5lIHZhIHBhcyBzdWZmaXJlIHBvdXIgcsOpY3Vww6lyZXIgbGVzIGluZm9ybWF0aW9ucyBkZXB1aXMgbGVzIGRvbm7DqWVzIGQnb3JpZ2luZcKgOiB1biBmb3JtYXRhZ2Ugc3VwcGzDqW1lbnRhaXJlIHByw6lhbGFibGUgc2UgcsOpdsOobGUgbsOpY2Vzc2FpcmUuDQoNCiMjIyMgRm9ybWF0ZXIgbGVzIGNoYcOubmVzIGRlIGNhcmFjdMOocmVzDQoNCmBgYHtyIGRhdGUtZm9ybWF0fQ0KIycgRm9ybWF0IGRhdGVzIGZyb20gYSBzdHJpbmcgdmVjdG9yIHNvIHRoZXkgbWF0Y2ggb3VyIHN0cmljdCByZWdleC4NCiMnIEBwYXJhbSBzdHJfdiBTdHJpbmcgdmVjdG9yIGNvbnRhaW5pbmcgZGF0ZSB0byBmb3JtYXQuDQojJyBAcmV0dXJuIFN0cmluZyB2ZWN0b3Igd2l0aCBkYXRlcyBmb3JtYXR0ZWQuDQpmb3JtYXRfZGF0ZXMgPC0gZnVuY3Rpb24oc3RyX3YpIHsNCiAgcmVzX3N0cl92IDwtDQogICAgc3RyX3YgJT4lDQogICAgIyAxLiBMb3dlcmNhc2UuDQogICAgc3RyX3RvX2xvd2VyKCkgJT4lDQogICAgIyAyLiBSZW1vdmUgZXZlcnkgd2hpdGVzcGFjZXMsIGFzIHRoZXkgYXJlIG1lYW5pbmdsZXNzLg0KICAgIHN0cl9yZXBsYWNlX2FsbCgiICIsICIiKSAlPiUNCiAgICAjIDMuIFJlcGxhY2UgaXJyZWd1bGFyIHZhbHVlcyB0byBob21vZ2VuaXplLg0KICAgIHN0cl9yZXBsYWNlX2FsbChjKA0KICAgICAgIi8iID0gIi0iLA0KICAgICAgInByZXxiZWZvcmUiID0gImFudGUiDQogICAgKSkgJT4lDQogICAgIyA0LiBGaXggc29tZSB3cml0aW5nIGVycm9ycy4NCiAgICAjIHJxOiBIZXJlIHdlIHRlbXBvcmFyeSB1c2Ugd2hpdGVzcGFjZXMNCiAgICAjIGFzIHRoZXkgYXJlIG5pY2VyIHRoYW4gbG9va2Fyb3VuZHMsIGVnLiAiKD88PVxkKWJjdyg/PS18JCkiDQogICAgc3RyX3JlcGxhY2VfYWxsKCIoW2Etel0rKSIsICIgXFwxICIpICU+JQ0KICAgIHN0cl9yZXBsYWNlX2FsbChjKA0KICAgICAgIiBlICIgPSAiY2UiLA0KICAgICAgIiBjZXIgIiA9ICJjZSIsDQogICAgICAiIGJlICIgPSAiYmNlIiwNCiAgICAgICIgYmMgIiA9ICJiY2UiLA0KICAgICAgIiBiY3cgIiA9ICJiY2UiLA0KICAgICAgIiBiY2ViY2UgIiA9ICJiY2UiDQogICAgKSkgJT4lDQogICAgc3RyX3JlcGxhY2VfYWxsKCIgIiwgIiIpICU+JQ0KICAgICMgNS4gUmVtb3ZlIHRyYWlsaW5nICItIi4NCiAgICBzdHJfcmVwbGFjZV9hbGwoIi0kIiwgIiIpICU+JQ0KICAgICMgNi4gQWRkIGNlL2JjZSBvbiB0aGUgbGVmdCBzaWRlIHdoZW4gaXQgaXMgbWlzc2luZy4NCiAgICAjIEBXQVJOOiBIZXJlLCB3ZSB1c2UgbG9va2FoZWFkIHRvIGNvcHkgdGhlIHJpZ2h0IHNpZGUgdG8gdGhlIGxlZnQgc2lkZSwNCiAgICAjIGFzIGlmIGl0IHdlcmUgYSBjb21tb24gZmFjdG9yLg0KICAgICMgSW4gb3VyIGRhdGEgdGhpbmdzIHNlZW0gdG8gYmUgZG9pbmcgZmluZSwNCiAgICAjIGJ1dCB0aGlzIG1ldGhvZCBkb2VzIG5vdCBoYW5kbGUgdGhlIGh5cG90aGV0aWNhbCBjYXNlDQogICAgIyB3aGVyZSBsZWZ0LXNpZGUgd291bGQgYmUgQkNFIGFuZCByaWdodCBDRS4NCiAgICAjIEluIHRoaXMgY2FzZSwgd2Ugd291bGQga25vdyB0aGF0LA0KICAgICMgY29uc2lkZXJpbmcgbGVmdCBjb21lcyBjaHJvbm9sb2dpY2FsbHkgYmVmb3JlIHJpZ2h0Og0KICAgICMgLSBJZiByaWdodCBpcyBCQ0UsIHRoZW4gbGVmdCBpcyBhbHNvIEJDRTsNCiAgICAjIGVnLiAyMDAtMTAwYmNlIG11c3QgYmUgMjAwYmNlLTEwMGJjZQ0KICAgICMgLSBJZiByaWdodCBpcyBDRSwgdGhlbiBsZWZ0IGlzIEJDRQ0KICAgICMgaWYgZGlnaXRzIG9uIHRoZSBsZWZ0IGFyZSBncmVhdGVyIHRoYW4gdGhlIG9uZXMgb24gdGhlIHJpZ2h0Ow0KICAgICMgZWcuIDIwMC0xMDBjZSBtdXN0IGJlIDIwMGJjZS0xMDBjZQ0KICAgICMgLSBJZiB0aGVyZSBhcmUgbm90LCB3ZSBjYW5ub3QgYmUgc3VyZSBpZiBsZWZ0IGlzIENFIG9yIEJDRS4NCiAgICAjIGVnLiA1MC0xMDBjZSBjYW5ub3QgYmUgZGV0ZXJtaW5lZA0KICAgICMgU28gd2Ugd291bGQgbmVlZCB0byBtYXRjaCwgcGFyc2UgdG8gbnVtYmVyLCBhbmQgY29tcGFyZSBlYWNoIHNpZGUuDQogICAgc3RyX3JlcGxhY2VfYWxsKCIoXFxkKSg/PS1cXGQrKGJjZXxjZSkpIiwgIlxcMVxcMiIpDQogICMgNy4gRGVsZXRlIGVsZW1lbnRzIHRoYXQgc3RpbGwgZG9uJ3QgcGFzcyB0aGUgcmVnZXgsDQogICMgdGhlcmUgYXJlIG5vdCB2YWxpZCBkYXRlcyBhbmQgd2UgY2Fubm90IG1ha2UgdGhlbSBmaXQgaW50byBvbmUuDQogICMgSW4gb3VyIGRhdGEsIHdlIGFyZSBsZWZ0IHdpdGggInJob2RlcyIgYW5kICJyb21lLGl0YWx5Ii4NCiAgIyBUaGV5IGFyZSBub3QgZGF0ZXMuIFdlIGZpeCB0aG9zZSB0d28gaW4gcHJldmlvdXMgc2VjdGlvbnMgb2YgdGhlIGRvY3VtZW50Lg0KICByZXNfc3RyX3YgPC0gcmVzX3N0cl92ICU+JQ0KICAgIHN0cl9kZXRlY3QocGFzdGUwKCJeIixkYXRlX3JlZ2V4LCIkIikpICU+JQ0KICAgIGlmX2Vsc2UocmVzX3N0cl92LCBOQV9jaGFyYWN0ZXJfKQ0KDQogIHJldHVybihyZXNfc3RyX3YpDQp9DQpgYGANCg0KYGBge3IgZGF0ZS1mb3JtYXQtdGVzdCwgZXZhbCA9IEZBTFNFfQ0KIyBUZXN0IHRvIGltcHJvdmUgZm9ybWF0dGluZyBncmFkdWFsbHksIHdlIGxvb2sgYXQgd2hhdCBkb2VzIG5vdCBwYXNzIHRoZSByZWdleC4NCnRlc3RfY29sc19kYXRlcyAlPiUNCiAgZm9ybWF0X2RhdGVzKCkgJT4lDQogIHN0cl9zdWJzZXQocGFzdGUwKCJeIixkYXRlX3JlZ2V4LCIkIiksIG5lZ2F0ZSA9IFRSVUUpDQpgYGANCg0KIyMjIyBDb252ZXJ0aXIgbGVzIGNhcmFjdMOocmVzIGVuIG5vbWJyZXMNCg0KYGBge3IgZGF0ZS1jb252ZXJ0fQ0KIycgSGVscGVyIGZ1bmN0aW9uLg0KIycgQ29udmVydCBhIHNpZGUgb2YgdGhlIGludGVydmFsIGludG8gYSBudW1iZXIuDQojJyBAcGFyYW0gbWF0Y2ggU3RyaW5nIHZlY3Rvci4gUmVsZXZhbnQgcG9ydGlvbiBvZiBhIG1hdGNoIGZyb20gY29udmVydF9kYXRlcygpDQojJyBAcmV0dXJuIE51bWJlciwgZGF0ZSBhcyBudW1iZXINCmhscF9jb252ZXJ0X3NpbmdsZV9kYXRlIDwtIGZ1bmN0aW9uKG1hdGNoKSB7DQogIGlzX2JjZSA8LSBpZl9lbHNlKG1hdGNoWywgM10gPT0gImJjZSIsIFRSVUUsIEZBTFNFKQ0KICBudW1iZXIgPC0gcGFyc2VfbnVtYmVyKG1hdGNoWywgMl0pDQogIG51bWJlciA8LSBpZl9lbHNlKGlzX2JjZSwgLW51bWJlciwgbnVtYmVyKQ0KICByZXR1cm4obnVtYmVyKQ0KfQ0KIycgQ29udmVydCBkYXRlcyBpbnRvIGEgbnVtYmVyLCB3aGljaCBpcyB0aGUgeWVhci4NCiMnIENFIHllYXJzIGFyZSBwb3NpdGl2ZSB2YWx1ZXMsIEJDRSB5ZWFycyBhcmUgbmVnYXRpdmUgdmFsdWVzLg0KIycgSWYgdGhlIGRhdGUgaW5jbHVkZXMgYW4gaW50ZXJ2YWwsIHRha2UgdGhlIG1lYW4gb2YgdGhlIGludGVydmFsLg0KIycgQHBhcmFtIHN0cl92IFN0cmluZyB2ZWN0b3IgY29udGFpbmluZyBkYXRlIHRvIGNvbnZlcnQuDQojJyBAcmV0dXJuIE51bWJlciB2ZWN0b3Igd2l0aCBjb252ZXJ0ZWQgZGF0ZXMuDQpjb252ZXJ0X2RhdGVzIDwtIGZ1bmN0aW9uKHN0cl92KSB7DQogIG1hdGNoIDwtIHN0cl9tYXRjaChzdHJfdiwgZGF0ZV9yZWdleCkNCiAgbGVmdF9udW1iZXIgPC0gaGxwX2NvbnZlcnRfc2luZ2xlX2RhdGUobWF0Y2hbLCAyOjVdKQ0KICByaWdodF9udW1iZXIgPC0gaGxwX2NvbnZlcnRfc2luZ2xlX2RhdGUobWF0Y2hbLCA2OjldKQ0KICByZXNfbnVtYmVyIDwtIG1hcDJfZGJsKA0KICAgIGxlZnRfbnVtYmVyLA0KICAgIHJpZ2h0X251bWJlciwNCiAgICB+IG1lYW4oYygueCwgLnkpLCBuYS5ybSA9IFRSVUUpDQogICkNCiAgcmV0dXJuKHJlc19udW1iZXIpDQp9DQpgYGANCg0KYGBge3IgZGF0ZS1jb252ZXJ0LXRlc3QsIGV2YWwgPSBGQUxTRX0NCnRlc3RfY29sc19kYXRlcyAlPiUNCiAgZm9ybWF0X2RhdGVzKCkgJT4lDQogIGNvbnZlcnRfZGF0ZXMoKQ0KYGBgDQoNCiMjIyMgQXBwbGljYXRpb24gYXV4IGRvbm7DqWVzDQoNCmBgYHtyIGRhdGUtYXBwbHl9DQojJyBQYXJzZSBkYXRlcyBmcm9tIGEgZGF0YWZyYW1lLg0KIycgQHBhcmFtIGRmIERhdGFmcmFtZSBjb250YWluaW5nIGRhdGUgY29sdW1ucyB0byBwYXJzZS4NCiMnIEByZXR1cm4gRGF0YWZyYW1lIHdpdGggZGF0ZXMgcGFyc2VkLg0KIycgQHNlZSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80NTk0Nzc4Ny9jcmVhdGUtbmV3LXZhcmlhYmxlcy13aXRoLW11dGF0ZS1hdC13aGlsZS1rZWVwaW5nLXRoZS1vcmlnaW5hbC1vbmVzDQpwYXJzZV9kYXRlc19kZiA8LSBmdW5jdGlvbihkZikgew0KICAjIENvbHVtbnMgdGhhdCB3ZSB3aWxsIGNvbXB1dGUgb24NCiAgY29scyA8LSBjKCJkYXRlX2FjdGl2ZSIsICJkYXRlX2JlZ2luIiwgImRhdGVfZW5kIikNCg0KICByZXNfZGYgPC0NCiAgICBkZiAlPiUNCiAgICAjIDEuIEFwcGx5IHRoZSBmdW5jdGlvbnMgdG8gZXZlcnkgY29sdW1ucyB3ZSBzZWxlY3RlZC4NCiAgICBtdXRhdGUoYWNyb3NzKA0KICAgICAgLmNvbHMgPSBhbGxfb2YoY29scyksDQogICAgICAuZm5zID0gbGlzdCgNCiAgICAgICAgc3RyID0gZm9ybWF0X2RhdGVzLA0KICAgICAgICBudW0gPSB+IGZvcm1hdF9kYXRlcyguKSAlPiUgY29udmVydF9kYXRlcygpDQogICAgICApLA0KICAgICAgLm5hbWVzID0gIntjb2x9X3tmbn0iDQogICAgKSkgJT4lDQogICAgIyAyLiBEcm9wIG9yaWdpbmFsIGNvbHVtcyB0byByZXBsYWNlIHRoZW0gd2l0aCB0aGVpciBudW1lcmljIGVxdWl2YWxlbnQNCiAgICBzZWxlY3QoLWFsbF9vZihjb2xzKSkgJT4lDQogICAgcmVuYW1lX2F0KA0KICAgICAgcGFzdGUwKGNvbHMsIl9udW0iKSwNCiAgICAgIH4gY29scw0KICAgICkgJT4lDQogICAgIyAzLiBSZWdyb3VwIGNvbHVtbnMgYnkgdHlwZQ0KICAgIHJlbG9jYXRlKGFsbF9vZihjb2xzKSwgLmJlZm9yZSA9ICJkYXRlX2FjdGl2ZV9zdHIiKQ0KDQogIHJldHVybihyZXNfZGYpDQp9DQoNCnBoaV9hdXRob3JzX2RmIDwtIHBoaV9hdXRob3JzX2RmICU+JQ0KICBwYXJzZV9kYXRlc19kZigpDQp0bGdfYXV0aG9yc19kZiA8LSB0bGdfYXV0aG9yc19kZiAlPiUNCiAgcGFyc2VfZGF0ZXNfZGYoKQ0KYGBgDQoNCmBgYHtyIGRhdGUtY2xlYW4sIGVjaG8gPSBGQUxTRSwgZXZhbCA9IEZBTFNFfQ0KIyBXZSByZW1vdmUgb2JqZWN0cyB0aGF0IHdlIHdpbGwgbm90IG5lZWQgYW55IGZ1cnRoZXIuDQpyZW1vdmUodGVzdF9kYXRlcywgdGVzdF9jb2xzX2RhdGVzKQ0KYGBgDQoNCiMjIyMgUsOpc3Vtw6kgZGVzIGRhdGVzIG9idGVudWVzDQoNCmBgYHtyfQ0KIyBCZXdhcmUsIHRoZSBjb2RlIHdyaXRpbmcgaXMgbm90IGdyZWF0IGhlcmUsDQojIGl0IGhhcyBiZWVuIGRvbmUgcXVpY2tseS4NCiMgVG8gaW1wcm92ZSwgb25lIGNvdWxkIGxvb2sgYXQgZHlwbHI6OnN1bW1hcmlzZSgpLCBvciBza2ltcg0KIycgQHBhcmFtIGRmIERhdGFmcmFtZS4NCiMnIEByZXR1cm4gTlVMTC4gSXQgcHJpbnRzIHRoZSBzdW1tYXJ5Lg0KcHJpbnRfZGF0ZV9zdW1tYXJ5IDwtIGZ1bmN0aW9uKGRmKSB7DQogIHRtcF9jb2xzIDwtIGxpc3QoDQogICAgICBkZiRkYXRlX2FjdGl2ZSwNCiAgICAgIGRmJGRhdGVfYmVnaW4sDQogICAgICBkZiRkYXRlX2VuZA0KICAgICkgJT4lDQogICAgdHJhbnNwb3NlKCkNCiAgdGliYmxlKA0KICAgIGNvbF9uYW1lID0gYygiZGF0ZV9hY3RpdmUiLCAiZGF0ZV9iZWdpbiIsICJkYXRlX2VuZCIpLA0KICAgIG1pbiA9IHBtYXBfZGJsKHRtcF9jb2xzLCBtaW4sIG5hLnJtID0gVFJVRSksDQogICAgbWF4ID0gcG1hcF9kYmwodG1wX2NvbHMsIG1heCwgbmEucm0gPSBUUlVFKQ0KICApDQp9DQpgYGANCg0KLS0tDQoNCiMjIyMjIEF1dGV1cnMgbGF0aW5zDQoNCmBgYHtyfQ0KcHJpbnRfZGF0ZV9zdW1tYXJ5KHBoaV9hdXRob3JzX2RmKQ0KYGBgDQoNCkxlcyBhdXRldXJzIGxhdGlucyBxdWUgbm91cyBhdm9ucyBzZSByw6lwYXJ0aXNzZW50LCBnbG9iYWxlbWVudCwgZHUgVkllIHNpw6hjbGUgYXZhbnQgbm90cmUgw6hyZSwgYXUgVkllIHNpw6hjbGUgZGUgbm90cmUgw6hyZS4NCg0KLS0tDQoNCiMjIyMjIEF1dGV1cnMgZ3JlY3MNCg0KYGBge3J9DQpwcmludF9kYXRlX3N1bW1hcnkodGxnX2F1dGhvcnNfZGYpDQpgYGANCg0KTGVzIGF1dGV1cnMgZ3JlY3MgcXVlIG5vdXMgYXZvbnMgc2UgcsOpcGFydGlzc2VudCwgZ2xvYmFsZW1lbnQsIGR1IFZJSUllIHNpw6hjbGUgYXZhbnQgbm90cmUgw6hyZSwgYXUgWFZJZSBzacOoY2xlIGRlIG5vdHJlIMOocmUuDQoNCiMjIyAxLjMuIEZvcm1hdGFnZSBkZXMgbGlldXgNCg0KUG91ciBzJ2Fzc3VyZXIgZGUgbCdob21vZ8OpbsOpaXTDqSBkZXMgZG9ubsOpZXMsIHRvdXQgZW4gZ2FnbmFudCBlbiBnw6luw6lyYWxpdMOpLCBub3VzIG4nYWxsb25zIGdhcmRlciBlbiBtYXRpw6hyZSBkZSBsaWV1IHF1ZSBsZSBwYXlzLCBlbiBsYWlzc2FudCBkZSBjw7R0w6kgZGVzIGluZGljYXRpb25zIHBsdXMgcHLDqWNpc2VzIGNvbW1lIGxhIHZpbGxlLiBOb3VzIG5lIGdhcmRvbnMgw6lnYWxlbWVudCBhcmJpdHJhaXJlbWVudCBxdSd1biBzZXVsIHBheXMgbG9yc3F1ZSBwbHVzaWV1cnMgc29udCBpbmRpcXXDqXMuDQoNCmBgYHtyIHBsYWNlLWZ1bmN0aW9ufQ0KIycgRm9ybWF0IHBsYWNlcy4NCiMnIE9ubHkgdGhlIG1vc3QtbGVmdCBzdHJpbmcsIHVuaW50ZXJydXB0ZWQgYnkgYSBjb21tYSwgaXMga2VwdC4NCiMnIEBwYXJhbSBkZiBEYXRhZnJhbWUNCiMnIEByZXR1cm4gRGF0YWZyYW1lDQpmb3JtYXRfcGxhY2VzX2RmIDwtIGZ1bmN0aW9uKGRmKSB7DQogIHJlc19kZiA8LQ0KICAgIGRmICU+JQ0KICAgIHJvd3dpc2UoKSAlPiUNCiAgICBtdXRhdGUoDQogICAgICBwbGFjZSA9IHBsYWNlICU+JQ0KICAgICAgICAjIDEuIFNwbGl0IGJ5IGNvbW1hIG9yIHNpbWlsYXIgc2lnbnMgdGhhdCBhcmUgYWxzbyB1c2VkLg0KICAgICAgICAjIENvbW1hIGFuZCBzbGFzaCBhcmUgbWVhbmluZ2Z1bCwNCiAgICAgICAgIyBidXQgZG90cyBvciBkb3VibGUgYmFja3NsYXNoZXMgc2VlbSB0byBiZSBtaXN0YWtlcy4NCiAgICAgICAgc3RyX3NwbGl0KCAiLHwvfFxcLnxcXFxcIikgJT4lDQogICAgICAgICMgMi4gS2VlcCBvbmx5IHRoZSBsYXN0IHBhcnQNCiAgICAgICAgdW5saXN0KCkgJT4lDQogICAgICAgIGxhc3QoKSAlPiUNCiAgICAgICAgIyAzLiBDbGVhbiB0aGUgcmVzdWx0IGZvciBob21vZ2VuZWl0eQ0KICAgICAgICBzdHJfdHJpbSgpICU+JQ0KICAgICAgICBzdHJfdG9fdGl0bGUoKSAlPiUNCiAgICAgICAgc3RyX3JlcGxhY2VfYWxsKCJcXD8iLCAiIikgJT4lDQogICAgICAgICMgNC4gRml4IHNvbWUgd3JpdGluZyBlcnJvcnMuDQogICAgICAgIHN0cl9yZXBsYWNlX2FsbChjKA0KICAgICAgICAgICJMaWJ5JCIgPSAiTGlieWEiLA0KICAgICAgICAgICJDeXJwdXMiID0gIkN5cHJ1cyINCiAgICAgICAgKSkNCiAgICApICU+JQ0KICAgIHVuZ3JvdXAoKQ0KICByZXR1cm4ocmVzX2RmKQ0KfQ0KYGBgDQoNCmBgYHtyIHBsYWNlLXRlc3QsIGV2YWwgPSBGQUxTRX0NCiMgQ2hlY2sgdGhhdCBmaW5hbCBwbGFjZXMgYXJlIHVuaXF1ZS4NCnRlc3RfcGxhY2VzIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGRmICU+JQ0KICAgIGZvcm1hdF9wbGFjZXNfZGYoKSAlPiUNCiAgICBkaXN0aW5jdChwbGFjZSkgJT4lDQogICAgYXJyYW5nZShwbGFjZSkgJT4lDQogICAgcHVsbChwbGFjZSkNCn0NCnRlc3RfcGxhY2VzKHBoaV9hdXRob3JzX2RmKQ0KdGVzdF9wbGFjZXModGxnX2F1dGhvcnNfZGYpDQpgYGANCg0KYGBge3IgcGxhY2UtYXBwbHl9DQpwaGlfYXV0aG9yc19kZiA8LSBmb3JtYXRfcGxhY2VzX2RmKHBoaV9hdXRob3JzX2RmKQ0KdGxnX2F1dGhvcnNfZGYgPC0gZm9ybWF0X3BsYWNlc19kZih0bGdfYXV0aG9yc19kZikNCmBgYA0KDQojIyMjIFLDqXN1bcOpIGRlcyBsaWV1eCBvYnRlbnVzDQoNCi0tLQ0KDQojIyMjIyBBdXRldXJzIGxhdGlucw0KDQpgYGB7ciBwbGFjZS1zdGF0cy1waGl9DQpwaGlfYXV0aG9yc19kZiAlPiUNCiAgZGlzdGluY3QocGxhY2UpICU+JQ0KICBhcnJhbmdlKHBsYWNlKSAlPiUNCiAgcHVsbCgpICU+JQ0KICBwcmludF92ZWN0b3IoKQ0KcGhpX2F1dGhvcnNfZGYgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG5hX24gPSBzdW0oaXMubmEocGxhY2UpKSwNCiAgICBuYV9yYXRlID0gcm91bmQobmFfbiAvIG4sIDMpDQogICkNCmBgYA0KDQotLS0NCg0KIyMjIyMgQXV0ZXVycyBncmVjcw0KDQpgYGB7ciBwbGFjZS1zdGF0cy10bGd9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZGlzdGluY3QocGxhY2UpICU+JQ0KICBhcnJhbmdlKHBsYWNlKSAlPiUNCiAgcHVsbCgpICU+JQ0KICBwcmludF92ZWN0b3IoOCkNCnRsZ19hdXRob3JzX2RmICU+JQ0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBuYV9uID0gc3VtKGlzLm5hKHBsYWNlKSksDQogICAgbmFfcmF0ZSA9IHJvdW5kKG5hX24gLyBuLCAzKQ0KICApDQpgYGANCg0KIyMjIDEuNC4gQWRqb25jdGlvbiBkZXMgZ2VucmVzDQoNCk9uIGFqb3V0ZSBmaW5hbGVtZW50IGxlcyBnZW5yZXMsIGRlcHVpcyBsZXMgZG9ubsOpZXMgZHUgQ0xUSy4gTG9yc3F1J2lsIHkgYXVyYSBwbHVzaWV1cnMgZ2VucmVzIHBvdXIgdW4gbcOqbWUgYXV0ZXVyLCBvbiBuZSBjb25zZXJ2ZXJhIHF1ZSBsZSBwcmVtaWVyIGdlbnJlIGRhbnMgbCdvcmRyZSBhbHBoYWLDqXRpcXVlLg0KDQpgYGB7ciBnZW5yZS1hcHBseX0NCnRtcF90bGdfZXBpdGhldHNfZGYgPC0NCiAgdGxnX2VwaXRoZXRzX3Jhd19kZiAlPiUNCiAgdW5uZXN0KGNvbHMgPSBjb2RlKSAlPiUNCiAgbXV0YXRlKGNvZGUgPSBjb2RlICU+JQ0KICAgIHVubGlzdCgpICU+JQ0KICAgIHBhcnNlX251bWJlcigpDQogICkgJT4lDQogIGRpc3RpbmN0KGNvZGUsIC5rZWVwX2FsbCA9IFRSVUUpDQp0bGdfYXV0aG9yc19kZiA8LSB0bGdfYXV0aG9yc19kZiAlPiUNCiAgbGVmdF9qb2luKHRtcF90bGdfZXBpdGhldHNfZGYsIGJ5ID0gImNvZGUiKSAlPiUNCiAgcmVsb2NhdGUoZ2VucmUsIC5hZnRlciA9IG5hbWUpDQpyZW1vdmUodG1wX3RsZ19lcGl0aGV0c19kZikNCmBgYA0KDQojIyMjIFLDqXN1bcOpIGRlcyBnZW5yZXMgb2J0ZW51cw0KDQpgYGB7ciBnZW5yZS1saXN0fQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGRpc3RpbmN0KGdlbnJlKSAlPiUNCiAgYXJyYW5nZShnZW5yZSkgJT4lDQogIHB1bGwoKSAlPiUNCiAgcHJpbnRfdmVjdG9yKDYpDQpgYGANCg0KTGVzIGRvbm7DqWVzIG9idGVudWVzIGRpcmVjdGVtZW50IGRlcHVpcyBsZSBmaWNoaWVyIGR1IENMVEsgcGFyYWlzc2VudCBuZSBwYXMgY29tcG9ydGVyIGQnaXJyw6lndWxhcml0w6lzIGV0IGRvbmMgbmUgcGFzIG7DqWNlc3NpdGVyIGRlIG5ldHRveWFnZSBzdXBwbMOpbWVudGFpcmUuDQoNCmBgYHtyIGdlbnJlLXN0YXRzfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG5hX24gPSBzdW0oaXMubmEoZ2VucmUpKSwNCiAgICBuYV9yYXRlID0gcm91bmQobmFfbiAvIG4sIDMpDQogICkNCnRsZ19hdXRob3JzX2RmICU+JSBzbGljZSgzMTo0MCkNCmBgYA0KDQpOb3RvbnMgbsOpYW5tb2lucyBxdSdpbCBhdXJhaXQgw6l0w6kgcGx1cyBlZmZpY2FjZSBkZSByw6ljdXDDqXJlciBsJ2luZm9ybWF0aW9uIGRlcyBnZW5yZXMgZGlyZWN0ZW1lbnQgc3VyIGxlIG5vbSBkZXMgYXV0ZXVyc8KgOiBlbiBjYWxjdWxhbnQgbGVzIHZhbGV1cnMgbWFucXVhbnRlcywgb24gdm9pdCBxdSdpbCBub3VzIGVuIG1hbnF1ZSBwbHVzIGQndW4gdGllcnMsIGV0IGVuIGNvbnN1bHRhbnQgbGUgY29udGVudSBkZXMgdGFibGVhdXggKGNpLWRlc3N1cyB1biBleHRyYWl0KSwgb24gcydhcGVyw6dvaXQgcXVlIGJpZW4gc291dmVudCBsJ8OpcGl0aMOodGUgcXVpIGFwcGFyYcOudCBwb3VydGFudCBkYW5zIGxlIG5vbSBuJ2FwcGFyYcOudCBwYXMgZGFucyBsYSBjb2xvbm5lIGfDqW7DqXLDqWUgw6AgcGFydGlyIGRlcyBkb25uw6llcyBkdSBDTFRLLg0KDQojIyMgMS41LiBGb3JtYXRhZ2VzIHN1cHBsw6ltZW50YWlyZXMNCg0KUG91ciB0ZXJtaW5lciBldCBmYWNpbGl0ZXIgbGVzIGFuYWx5c2VzIGdyYXBoaXF1ZXMgc3VpdmFudGVzLCBub3VzIGFsbG9ucyBjcsOpZXIgZGV1eCBub3V2ZWxsZXMgdmFyaWFibGVzwqA6DQoNCi0gKipsJ2luaXRpYWxlKirCoDogcG91ciDDqXZpdGVyIGQnYXZvaXIgw6AgdHJhaXRlciBkZXMgbWlsbGllcnMgZGUgbm9tcyBkJ2F1dGV1cnMgYWxvcnMgcXVlIG5vdXMgbm91cyBpbnTDqXJlc3Nlcm9ucyDDoCB1biBwb3NzaWJsZSBjbGFzc2VtZW50IGFscGhhYsOpdGlxdWUsIG5vdXMgcG91cnJvbnMgYWluc2kgbmUgcmV0ZW5pciBxdWUgbGV1ciBpbml0aWFsZS4gQ2VsYSBub3VzIHBlcm1ldHRyYSDDqWdhbGVtZW50IGQnYWZmaWNoZXIgZGVzIGNvdWxldXJzIGVuIGZvbmN0aW9uIGRlcyBpbml0aWFsZXMsIGNlbGxlcy1jaSBjb25zdGl0dWFudCB1bmUgdmFyaWFibGUgY2F0w6lnb3JpZWxsZcKgOw0KDQotICoqbGEgZGF0ZSoqwqA6IG9uIHByZW5kcmEgYXJiaXRyYWlyZW1lbnQgbGUgcGx1cyBzb3V2ZW50IGxlIHNpw6hjbGUgZCdhY3Rpdml0w6kgY29tbWUgZGF0ZSBkZSByw6lmw6lyZW5jZSwgZCdvw7kgbm91cyBlbiBkdXBsaXF1b25zIGxhIGNvbG9ubmUgcG91ciB5IGFjY8OpZGVyIHBsdXMgZmFjaWxlbWVudC4NCg0KRGUgcGx1cywgbm91cyBzdXBwcmltb25zIGxlcyBjYXJhY3TDqHJlcyBpbmTDqXNpcmFibGVzIGF1IGTDqWJ1dCBkdSBub20gZGVzIGF1dGV1cnMsIHBvdXIgw6p0cmUgc8O7cnMgZGUgcsOpY3Vww6lyZXIgbCdpbml0aWFsZSBjb3JyZWN0ZW1lbnQgZXQgZCfDqnRyZSBjb25mb3JtZXMgw6AgbCdvcmRyZSBhbHBoYWLDqXRpcXVlLg0KDQpgYGB7ciBmb3JtYXQtY29tcGxlbWVudGFyeX0NCiMgTmV0dG95YWdlIGRlIHBhcmVudGjDqHNlcyBkaXZlcnNlcyBwb3VyIGxlIGZpY2hpZXIgVExHDQp0bGdfYXV0aG9yc19kZiRuYW1lIDwtIGdzdWIoIig8fFxcW3xcXCgpIiwgIiIsIHRsZ19hdXRob3JzX2RmJG5hbWUpDQoNCiMgQ3LDqWF0aW9uIGQndW5lIGNvbG9ubmUgZGVzIGluaXRpYWxlcyBkZXMgYXV0ZXVycw0KdGxnX2F1dGhvcnNfZGYkaW5pdCA8LSBzdWJzdHJpbmcodGxnX2F1dGhvcnNfZGYkbmFtZSwxLDEpDQpwaGlfYXV0aG9yc19kZiRpbml0IDwtIHN1YnN0cmluZyhwaGlfYXV0aG9yc19kZiRuYW1lLDEsMSkNCg0KIyBSw6lvcmdhbmlzYXRpb24gZGUgbCdvcmRyZSBkZXMgY29sb25uZXMNCnRsZ19hdXRob3JzX2RmIDwtIHRsZ19hdXRob3JzX2RmICU+JQ0KICByZWxvY2F0ZShpbml0LCAuYmVmb3JlID0gbmFtZSkNCnBoaV9hdXRob3JzX2RmIDwtIHBoaV9hdXRob3JzX2RmICU+JQ0KICByZWxvY2F0ZShpbml0LCAuYmVmb3JlID0gbmFtZSkNCg0KIyBBam91dCBkJ3VuZSBjb2xvbm5lICJkYXRlIiBxdWkgY29waWUgImRhdGVfYWN0aXZlIiwgcGFyIGNvbW1vZGl0w6kNCnRsZ19hdXRob3JzX2RmIDwtIHRsZ19hdXRob3JzX2RmICU+JQ0KICBtdXRhdGUoZGF0ZSA9IGRhdGVfYWN0aXZlLCAuYmVmb3JlID0gIGRhdGVfYWN0aXZlKQ0KcGhpX2F1dGhvcnNfZGYgPC0gcGhpX2F1dGhvcnNfZGYgJT4lDQogIG11dGF0ZShkYXRlID0gZGF0ZV9hY3RpdmUsIC5iZWZvcmUgPSAgZGF0ZV9hY3RpdmUpDQpgYGANCg0KIyMjIERvbm7DqWVzIGZpbmFsZXMgb2J0ZW51ZXMNCg0KKlBvdXIgc2F2b2lyIHBsdXMgcHLDqWNpc8OpbWVudCBjZSDDoCBxdW9pIGNvcnJlc3BvbmRlbnQgY2hhY3VuZSBkZXMgdmFyaWFibGVzIG9idGVudWVzLCByZW5kZXotdm91cyBbYXUgZMOpYnV0IGRlIGxhIHNlY3Rpb25dKCN2YXJpYWJsZXMtcmVjaGVyY2jDqWVzKcKgISoNCg0KLS0tDQoNCiMjIyMgQXV0ZXVycyBsYXRpbnMNCg0KYGBge3IgcGhpLWRhdGEtZmluYWx9DQpwaGlfYXV0aG9yc19kZg0Kc2tpbShwaGlfYXV0aG9yc19kZikNCmBgYA0KDQotLS0NCg0KIyMjIyBBdXRldXJzIGdyZWNzDQoNCmBgYHtyIHRsZy1kYXRhLWZpbmFsfQ0KdGxnX2F1dGhvcnNfZGYNCnNraW0odGxnX2F1dGhvcnNfZGYpDQpgYGANCg0KIyMgMi4gQW5hbHlzZXMgZ3JhcGhpcXVlcw0KDQpQb3VyIHRyb3V2ZXIgbGVzIGxvZ2lxdWVzIGludGVybmVzIGRlIGNsYXNzZW1lbnQsIG5vdXMgYWxsb25zIHByb2PDqWRlciBwcm9ncmVzc2l2ZW1lbnQsIGVuIGFuYWx5c2FudCBzdWNjZXNzaXZlbWVudCBsZXMgZGlmZsOpcmVudGVzIHZhcmlhYmxlcyBlbiBmb25jdGlvbiBkZSBsYSB2YXJpYWJsZSDDoCBleHBsaXF1ZXIsIGwnaWRlbnRpZmlhbnQuDQoNCk5vdXMgY29tbWVuY2Vyb25zIHBhciBhbmFseXNlciBsZXMgdmFyaWFibGVzIGRldXggw6AgZGV1eCwgZW4gcHJvamV0YW50IGxlcyBhdXRldXJzIHNlbG9uIHVuIG51YWdlIGRlIHBvaW50cy4gTCdpZGVudGlmaWFudCwgdmFyaWFibGUgw6AgZXhwbGlxdWVyLCBzZXJhIHN5c3TDqW1hdGlxdWVtZW50IHByb2pldMOpIGVuIGFic2Npc3NlLCBldCBsYSB2YXJpYWJsZSBwb3RlbnRpZWxsZW1lbnQgZXhwbGljYXRpdmUgZW4gb3Jkb25uw6llLg0KDQpQdWlzIG5vdXMgY2hlcmNoZXJvbnMgw6Agc2Fpc2lyIGRlcyBzb3VzLWxvZ2lxdWVzIGludGVybmVzIGVuIGFqb3V0YW50IHVuZSB0cm9pc2nDqG1lIHZhcmlhYmxlLCBjZSBxdWkgY29ycmVzcG9uZCDDoCB1bmUgInRyb2lzacOobWUgZGltZW5zaW9uIiBzdXIgbm9zIGdyYXBoaXF1ZXMsIHF1ZSBub3VzIG1hdMOpcmlhbGlzZXJvbnMgcGFyIGRlIGxhIGNvdWxldXIuDQoNClNpIG7DqWNlc3NhaXJlLCBhdSBmaWwgZGUgbm9zIGFuYWx5c2VzLCBub3VzIHBvdXJyb25zIHJldmVuaXIgZW4gImRldXggZGltZW5zaW9ucyIgc2kgY2VsYSBwYXJhw650IHBlcnRpbmVudMKg4oCTIMOpdmVudHVlbGxlbWVudCBlbiBjb2xvcmFudCB1bmUgZGVzIGRpbWVuc2lvbnMgcG91ciBkYXZhbnRhZ2UgZGUgY2xhcnTDqSB2aXN1ZWxsZSDigJMsIHBhciBleGVtcGxlIHN1ciB1bmUgc8OpcXVlbmNlIHBhcnRpY3VsacOocmXCoOKAkyBjYXIgaWwgc2UgcG91cnJhaXQgYmllbiBxdWUgbm91cyBkw6ljb3V2cmlvbnMgbCdleGlzdGVuY2UgZGUgInPDqXF1ZW5jZXMiIHBhcnRpY3VsacOocmVzLi4uDQoNCsOAIGNoYXF1ZSBmb2lzLCBvbiBhbmFseXNlcmEgbGVzIGF1dGV1cnMgZ3JlY3MsIHB1aXMgbGVzIGF1dGV1cnMgbGF0aW5zLiBBdSBmdXIgZXQgw6AgbWVzdXJlLCBvbiBzYWlzaXJhIGxlcyBsb2dpcXVlcyBzb3VzLWphY2VudGVzIGF1eCBjbGFzc2lmaWNhdGlvbnMgVExHIGV0IFBISS4NCg0KIyMjIEFuYWx5c2VzIGVuIGRldXggZGltZW5zaW9ucw0KDQojIyMgMi4xLiBMZXMgaWRlbnRpZmlhbnRzIHBhciBsZXMgbm9tcw0KDQpMYSBjbGFzc2lmaWNhdGlvbiBxdWkgcGFyYcOudHJhaXQgbGEgcGx1cyBpbnR1aXRpdmUgZXN0IGNlbGxlIGRlIGwnb3JkcmUgYWxwaGFiw6l0aXF1ZS4gVm95b25zIGRvbmMgc2kgbGVzIGNvZGVzIHNvbnQgY29ycsOpbMOpcyBvdSBub24gYXV4IG5vbXMgZGVzIGF1dGV1cnMgcHJvamV0w6lzIHBhciBvcmRyZSBhbHBoYWLDqXRpcXVlLg0KDQotLS0NCg0KIyMjIyBBdXRldXJzIGdyZWNzDQoNCmBgYHtyIHRsZy1jb2RlLW5hbWV9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZ2dwbG90KGFlcyhjb2RlLCBmY3RfcmVvcmRlcihuYW1lLCBkZXNjKG5hbWUpKSkpICArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBub21zIiwgIHggPSAiY29kZSIsIHkgPSAibmFtZSIpDQpgYGANCg0KQ2UgcHJlbWllciBncmFwaGlxdWUgcHLDqXNlbnRlIHVuIHByZW1pZXIgcHJvYmzDqG1lIDogbGVzIGRvbm7DqWVzIHNvbnQgdHLDqHMgbm9tYnJldXNlcywgc2kgYmllbiBxdWUgbGVzIHLDqXN1bHRhdHMgc29udCBwZXUgY2xhaXJzLiBPbiBvYnNlcnZlIG7DqWFubW9pbnMgcXVlIGxhIG1ham9yaXTDqSBkZXMgY29kZXMgc2UgdHJvdXZlbnQgZW50cmUgMCBldCAyNTAwLCBldCBsYSBncmFuZGUgbWFqb3JpdMOpIGVudHJlIDAgZXQgNTAwMC4gT24gcG91cnJhaXQgZG9uYyBzZSBjb25jZW50cmVyIHN1ciBjZXR0ZSBwb3J0aW9uLCBldCBtYXNxdWVyIGxlcyBub21zIGRlIHNvcnRlIMOgIGNlIHF1ZSBsZSBncmFwaGlxdWUgcHVpc3NlIGRhdmFudGFnZSBzJ8OpdGFsZXIuDQoNCmBgYHtyIHRsZy1jb2RlLW5hbWUtMC01MDAwfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgNTAwMCkgJT4lDQogZ2dwbG90KGFlcyhjb2RlLCBmY3RfcmVvcmRlcihuYW1lLCBkZXNjKG5hbWUpKSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHIGV0IG5vbXMgKDAtNTAwMCkiLCB4ID0gImNvZGUiLCB5ID0gIm5hbWUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEoMCwgNTAwMCwgYnkgPSAyMDApLDEpKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShzaXplID0gMC41LCBjb2xvciA9ICJncmV5IikNCiAgKQ0KYGBgDQoNCk9uIG9ic2VydmUgYXNzZXogY2xhaXJlbWVudCBkZXMgbGlnbmVzIGRyb2l0ZXMuIENlbGEgcmVzc2VtYmxlIMOgIGRlcyBzw6lyaWVzIGNvaMOpcmVudGVzIGRlIG5vbXMgY2xhc3PDqXMgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUgc3VyIGNlcnRhaW5lcyBwb3J0aW9ucy4gSWwgZmF1ZHJhaXQgZG9uYyBkw6ljb3VwZXIgbGVzIGNvZGVzIFRMRyBlbiBwbHVzaWV1cnMgc8OpcXVlbmNlcyBzdWNjZXNzaXZlcyBwb3VyIGVuIGFuYWx5c2VyIGxhIGxvZ2lxdWUgaW50ZXJuZS4NCg0KT24gb2JzZXJ2ZSBub3RhbW1lbnQgcXVlIGxlcyBkcm9pdGVzIHF1aSBhcHBhcmFpc3NlbnQgc2Ugc2l0dWVudCBhdmFudCBsZSBjb2RlIDE4MDDCoDogaWwgc2VtYmxlcmFpdCBkb25jIHF1ZSBsZXMgY29kZXMgdWx0w6lyaWV1cnMgb2LDqWlzc2VudCDDoCB1bmUgYXV0cmUgbG9naXF1ZSBxdWUgbGEgbG9naXF1ZSBhbHBoYWLDqXRpcXVlLCBhbG9ycyBxdSdhdmFudCAxODAwIGlsIHkgYXVyYWl0IHB1IGF2b2lyIGRlcyAiYWpvdXRzIHBhciB2YWd1ZXMgc3VjY2Vzc2l2ZXMiIMOgIGxhIGxpc3RlIGRlcyBpZGVudGlmaWFudHMsIGNoYXF1ZSB2YWd1ZSDDqXRhbnQgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUuDQoNCkludMOpcmVzc29ucy1ub3VzIHBsdXMgZW4gZMOpdGFpbCDDoCBsYSBzw6lxdWVuY2UgYXZhbnQgMTgwMC4NCg0KYGBge3J9DQojIFByZW1pw6hyZSB0ZW50YXRpdmUgZGUgY3LDqWVyIHVuIHZlY3RldXIgw6AgcGFydGlyIGRlcyBjb2RlcywNCiMgcG91ciBsZXMgZGl2aXNlciBlbiBwbHVzaWV1cnMgc8OpcXVlbmNlcywNCiMgZXQgZW4gdGlyZXIgZGVzIGluZm9ybWF0aW9ucyBwbHVzIGZhY2lsZW1lbnQuDQojY29kZV9hdXRob3JzX3RsZyA8LQ0KIyAgYXNfdGliYmxlKHRsZ19hdXRob3JzX2RmKSAlPiUNCiMgIHNsaWNlKGNvZGUpICU+JQ0KIyAgdW5saXN0KC4sIHVzZS5uYW1lcyA9IEZBTFNFKQ0KI3NwbGl0KGNvZGVfYXV0aG9yc190bGcsIDE6MjU0NSkNCg0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgMTgwMCkgJT4lDQogIGdncGxvdChhZXMoY29kZSwgZmN0X3Jlb3JkZXIobmFtZSwgZGVzYyhuYW1lKSkpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBub21zICgwLTE4MDApIiwgeCA9ICJjb2RlIiwgeSA9ICJuYW1lIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKDAsIDE4MDAsIGJ5ID0gMTAwKSwxKSkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNSwgY29sb3IgPSAiZ3JleSIpDQogICkNCg0KDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBub21zICgwLTUwMDApIikNCg0KYGBgDQoNCk9uIG9ic2VydmXCoDoNCg0KLSBVbmUgc8OpcXVlbmNlIMOpdmlkZW50ZSBkZSB+MTEwMCDDoCB+MTgwMC4gRWxsZSB2YSBkZSBwcmVzcXVlIGxlIGTDqWJ1dCBkZSBsJ2FscGhhYmV0LCDDoCBsYSBmaW4gZGUgbCdhbHBoYWJldMKgOw0KLSBEZXV4IHPDqXF1ZW5jZXMsIGRlIH4zOTAgw6AgfjUyMCwgZXQgZGUgfjc1MCDDoCB+MTEyMCwgcXVpIHMnw6l0ZW5kZW50IHRvdXQgbGUgbG9uZyBkZSBsJ2FscGhhYmV0wqA7DQotIFVuZSBzw6lxdWVuY2UgZGUgfjEwMCDDoCB+MjAwIHF1aSBzJ2FycsOqdGUgdmVycyBsZSBtaWxpZXUgZGUgbCdhbHBoYWJldMKgOw0KLSBVbmUgcGV0aXRlIHPDqXF1ZW5jZSBjb25jZW50csOpZSBhdSBkw6lidXQgZGUgbCdhbHBoYWJldCBlbnRyZSB+NjUwIGV0IH43NTAuIERhbnMgbCdhbHBoYWJldCAoZW4gb3Jkb25uw6llcyksIGVsbGUgc2VtYmxlIHMnYXJyw6p0ZXIgcHJvY2hlIGRlIGxhIHZhbGV1ciBvw7kgbGEgbG9uZ3VlIHRyYcOubsOpZSBkZSB+MTEwMCDDoCB+MTgwMCBjb21tZW5jZS4NCg0KRGUgcGx1cywgb24gcmVtYXJxdWUgcGx1c2lldXJzIMOpbMOpbWVudHPCoDoNCg0KLSBNw6ptZSBzdXIgY2V0dGUgcG9ydGlvbiwgaWwgeSBhIHBsdXNpZXVycyBzw6lxdWVuY2VzIGQnaWRlbnRpZmlhbnRzIHF1aSBwYXJhaXNzZW50IG5lIHBhcyBzdWl2cmUgbGEgbG9naXF1ZSBhbHBoYWLDqXRpcXVlIChlbiBwYXJ0aWN1bGllciBlbnRyZSAwIGV0IDEwMCwgZW50cmUgMjAwIGV0IDQwMCwgZW50cmUgNTIwIGV0IDY1MCkuIENlcyBzw6lxdWVuY2VzIHBvdXJyYWllbnQgc3VpdnJlIHVuZSBhdXRyZSBsb2dpcXVlLCBvdSBiaWVuIG5lIGNvcnJlc3BvbmRyZSDDoCByaWVuIGQnaWRlbnRpZmlhYmxlIGZhY2lsZW1lbnTCoOKAkyBpbCBwb3VycmFpdCBzJ2FnaXIgZCd1bmUgYXR0cmlidXRpb24gImF1IGhhc2FyZCIsIG91IGNvcnJlc3BvbmRyZSDDoCB1bmUgZW50csOpZSBkZXMgaWRlbnRpZmlhbnRzICJhdSBmaWwgZGUgbCdlYXUiIHNhbnMgbG9naXF1ZSBzeXN0w6ltYXRpcXVlIHByw6ktw6l0YWJsaWUsIHBhciBleGVtcGxlIGF1IGZ1ciBldCDDoCBtZXN1cmUgcXVlIGRlIG5vdXZlYXV4IGF1dGV1cnMgZW5yaWNoaXNzYWllbnQgbGUgY29ycHVzIFRMRy4NCg0KLSBNw6ptZSBzdXIgbGVzIHPDqXF1ZW5jZXMgb8O5IGwnb3JkcmUgYWxwaGFiw6l0aXF1ZSBwYXJhw650IHNpZ25pZmljYXRpZiwgaWwgeSBhIHBhcmZvaXMgcXVlbHF1ZXMgInBvaW50cyBhYmVycmFudHMiLCDDqWxvaWduw6lzIGRlIGxhIGRyb2l0ZSBxdWkgc2UgZGVzc2luZcKgOiBpbHMgc2VtYmxlbnQgbmUgcGFzIHN1aXZyZSBsYSBsb2dpcXVlIGRlIGxhIHPDqXF1ZW5jZSBkJ2lkZW50aWZpYW50cyBkYW5zIGxhcXVlbGxlIGlscyBzJ2luc8OocmVudC4gTGUgcGx1cyB2cmFpc2VtYmxhYmxlLCBjJ2VzdCBhbG9ycyBxdWUgbGUgbm9tIHF1ZSBub3VzIGF2b25zIGRhbnMgbm9zIGRvbm7DqWVzIG5lIGNvcnJlc3BvbmRlIHBhcyBhdSBub20gcXVpIGEgw6l0w6kgdXRpbGlzw6kgcG91ciBhdHRyaWJ1ZXIgbCdpZGVudGlmaWFudMKg4oCTIG91IGFsb3JzLCBsb3JzcXVlIGxlIG5vbSBlc3QgY29tcG9zw6kgZGUgcGx1c2lldXJzIHRlcm1lcywgcXVlIGNlbHVpIHBvc2l0aW9ubsOpIGVuIHByZW1pZXIgZGFucyBub3MgZG9ubsOpZXMgbmUgc29pdCBwYXMgY2VsdWkgcXVpIGFpdCBzZXJ2aSBwb3VyIGwnaW5kZXhhdGlvbiBhbHBoYWLDqXRpcXVlIGRlIGwnYXV0ZXVyLCBjb21tZSBkYW5zIGxlIGNhcyBkJ3VuIHByw6lub20gc3VpdmkgZCd1biBwYXRyb255bWUuDQoNCi0gRW5maW4sIG9uIHJlbWFycXVlIHVuIGFzcGVjdCBxdWkgcG91dmFpdCBkw6lqw6Agw6p0cmUgYWlzw6ltZW50IGNvbnN0YXTDqSBhdXBhcmF2YW50wqA6IGlsIGV4aXN0ZSBkZXMgImlkZW50aWZpYW50cyIgbWFucXVhbnRzLCBhdXhxdWVscyBhdWN1biBhdXRldXIgbmUgY29ycmVzcG9uZC4gQ2UgcGjDqW5vbcOobmUgc2VtYmxlIGFwcGFyYcOudHJlIMOpZ2FsZW1lbnQgYXUgc2VpbiBtw6ptZSBkZXMgc8OpcmllcyBhbHBoYWLDqXRpcXVlcy4gUGFyIGV4ZW1wbGXCoDoNCg0KYGBge3J9DQp0bGdfYXV0aG9yc19kZiAlPiUgZmlsdGVyKGNvZGUgPj0gODQwICYgY29kZSA8PSA4NTApDQpgYGANCg0KT24gb2JzZXJ2ZSBpY2kgcXUnZW50cmUgbGVzIGlkZW50aWZpYW50cyA4NDAgZXQgODUwLCBvbiBuZSB0cm91dmUgZW4gZmFpdCBxdWUgZGV1eCBpZGVudGlmaWFudHPCoDogbGUgODQ1IGV0IGxlIDg0OC4gTGVzIGlkZW50aWZpYW50cyA4NDAsIDg0MSwgODQyLCA4NDMsIDg0NCwgODQ2LCA4NDcsIDg0OSBldCA4NTAgc29udCAibWFucXVhbnRzIi4NCg0KQ2UgZGVybmllciBwaMOpbm9tw6huZSBuZSBwYXJhw650IHBhcyDDqXZpZGVudCDDoCBleHBsaXF1ZXIuIE5vdXMgdm95b25zIHBsdXNpZXVycyBoeXBvdGjDqHNlcyBxdWkgcGV1dmVudCDDqnRyZSBjb21wbMOpbWVudGFpcmVzLiBJbCBwb3VycmFpdCBzJ2FnaXIgZGUgc8OpcXVlbmNlcyBwcm9ncmFtbcOpZXMsIGxhIHBsYWdlIGxldXIgw6l0YW50IGFsb3JzIHLDqXNlcnbDqWUsIG1haXMgZmluYWxlbWVudCBub24gcsOpYWxpc8OpZXMsIG91IHLDqWFsaXPDqWVzIHVuaXF1ZW1lbnQgcGFydGllbGxlbWVudCwgcGFyIGV4ZW1wbGUgZHUgZmFpdCBkZSBjb3JwdXMgbm9uIHByw6p0cyBkYW5zIGxlcyB0ZW1wcy4gU2kgbGVzIHNhdXRzIGV4aXN0YWllbnQgYXUgbW9tZW50IG3Dqm1lIGRlIGwnYXR0cmlidXRpb24sIGlsIHNlIHBvdXJyYWl0IGF1dHJlbWVudCBxdSdpbHMgcmVsw6h2ZW50IGQnZXJyZXVycyBvdSBkJ2Fqb3V0cyBpbnRlbXBlc3RpZnMgYXUgc2VpbiBkJ3VuZSBzw6lyaWUgcGx1cyBsb25ndWUuIE9uIHBvdXJyYWl0IHNpbm9uIGltYWdpbmVyIHF1ZSBjZXMgInNhdXRzIiBwb3VycmFpZW50IGF1c3NpIMOqdHJlIGxlIHLDqXN1bHRhdCBkZSBtYW5pcHVsYXRpb25zIHVsdMOpcmlldXJlc8KgOiBsZXMgYXV0ZXVycyBxdWkgcG9zc8OpZGFpZW50IGNlcyBpZGVudGlmaWFudHMgYXVyYWllbnQgw6l0w6kgInLDqWF0dHJpYnXDqXMiLCBvdSBtw6ptZSB0b3V0IHNpbXBsZW1lbnQgc3VwcHJpbcOpcywgcG91ciB1bmUgcmFpc29uIG91IHBvdXIgdW5lIGF1dHJlLiBQb3VyIGF1dGFudCBjZXR0ZSBoeXBvdGjDqHNlIHNlbWJsZSBwZXUgcHJvYmFibGUsIGRhbnMgbGEgbWVzdXJlIG/DuSBsYSBtb2RpZmljYXRpb24gZGUgbCdpZGVudGlmaWFudCBkJ3VuIGNvcnB1cyBwdWJsacOpIHBvc2VyYWl0IGRlcyBwcm9ibMOobWVzIHRlY2huaXF1ZXMgZGUgcsOpYXR0cmlidXRpb24gZW4gY2hhw65uZSBwb3VyIHNvbiByw6lmw6lyZW5jZW1lbnQuDQoNCkNlcyBoeXBvdGjDqHNlcyBkZW1ldXJlbnQgc3DDqWN1bGF0aXZlcywgZGFucyBsYSBtZXN1cmUgb8O5IG5vdXMgbmUgZGlzcG9zb25zIHBhcyBkZSBsJ2hpc3RvcmlxdWUgZGUgY29uc3RpdHV0aW9uIGRlIGNlcyBiYXNlcyBkZSBkb25uw6llcy4gVW5lIHZhcmlhYmxlIGNvbW1lIGxhIGRhdGUgZCdlbnRyw6llIGR1IGNvcnB1cyBkYW5zIGxhIGJpYmxpb3Row6hxdWUgcG91cnJhaXQgaWNpIG5vdXMgw6ljbGFpcmVyLg0KDQojIyMjIEF1dGV1cnMgbGF0aW5zDQoNClBhc3NvbnMgYXV4IGF1dGV1cnMgbGF0aW5zLg0KDQpgYGB7ciBwaGktY29kZS1uYW1lfQ0KcGhpX2F1dGhvcnNfZGYgJT4lDQogIGdncGxvdChhZXMoY29kZSwgZmN0X3Jlb3JkZXIobmFtZSwgZGVzYyhuYW1lKSkpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFBISSBldCBub21zIiwgIHggPSAiY29kZSIsIHkgPSAibmFtZSIpDQpgYGANCg0KT24gdm9pdCBxdWUgbGEgZ3JhbmRlIG1ham9yaXTDqSBkZXMgaWRlbnRpZmlhbnRzIHNvbnQgaW5mw6lyaWV1cnMgw6AgMjUwMMKgOiBjb25jZW50cm9ucy1ub3VzIHN1ciBjZXR0ZSBwb3J0aW9uLg0KDQpgYGB7ciBwaGktY29kZS1uYW1lLTAtMjUwMH0NCnBoaV9hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIoY29kZSA8IDI1MDApICU+JQ0KICBnZ3Bsb3QoYWVzKGNvZGUsIGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBQSEkgZXQgbm9tcyAoMC0yNTAwKSIsIHggPSAiY29kZSIsIHkgPSAibmFtZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgwLCAyNTAwLCBieSA9IDEwMCksMSkpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSksDQogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjUsIGNvbG9yID0gImdyZXkiKQ0KICApDQpgYGANCg0KQ29udHJhaXJlbWVudCBhdXggYXV0ZXVycyBncmVjcyBkdSBUTEcsIGxlcyByw6lzdWx0YXRzIHBhcmFpc3NlbnQgY2V0dGUgZm9pcyBiZWF1Y291cCBtb2lucyDDqXZpZGVudHMsIGV0IGxhIGNvcnLDqWxhdGlvbiBlbnRyZSBsJ2lkZW50aWZpYW50IGV0IGxhIHBsYWNlIGR1IG5vbSBkYW5zIGwnb3JkcmUgYWxwaGFiw6l0aXF1ZSBlc3QgdW4gcGV1IGRvdXRldXNlLiBUb3V0IGF1IHBsdXMsIG9uIHBvdXJyYWl0IHBlbnNlciBxdSdpbCBleGlzdGUgdW5lIHBldGl0ZSB0ZW5kYW5jZSBkZSB+NDAwIMOgIH43MDAsIHZvaXJlIGVudHJlIH44MDAgZXQgfjEwNTAuIE1haXMgaWwgc2VtYmxlcmFpdCBxdWUgbGEgY2xhc3NpZmljYXRpb24gb2LDqWlzc2UgZXNzZW50aWVsbGVtZW50IMOgIGQnYXV0cmVzIGxvZ2lxdWVzLCBxdWUgbm91cyBhbGxvbnMgZMOpc29ybWFpcyB0ZW50ZXIgZCdleHBsb3Jlci4NCg0KIyMjIDIuMi4gTGVzIGlkZW50aWZpYW50cyBwYXIgbGVzIGRhdGVzDQoNCkFwcsOocyBsJ29yZHJlIGFscGhhYsOpdGlxdWUsIHVuZSBhdXRyZSBjbGFzc2lmaWNhdGlvbiBxdWkgcGFyYcOudHJhaXQgYXNzZXogaW50dWl0aXZlIGVzdCBsYSBjbGFzc2lmaWNhdGlvbiBjaHJvbm9sb2dpcXVlIHBhciBkYXRlcy4gTm91cyBhbGxvbnMgZG9uYyB2b2lyIGRhbnMgcXVlbGxlIG1lc3VyZSBsZXMgY29kZXMgVExHIGV0IFBISSBzb250IGV4cGxpY2FibGVzIHBhciBsJ8OpcG9xdWUgZGVzIGF1dGV1cnMsIHB1aXMgbm91cyBjcm9pc2Vyb25zIGVuc3VpdGUsIGRhbnMgbGEgcGFydGllIHN1aXZhbnRlLCBsYSBkYXRlIGF2ZWMgZCdhdXRyZXMgdmFyaWFibGVzLg0KDQotLS0NCg0KIyMjIyBBdXRldXJzIGdyZWNzDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGV9DQojIFByZW1pw6hyZSDDqXR1ZGUgZW4gbm9pciBldCBibGFuYw0KZ2dwbG90KHRsZ19hdXRob3JzX2RmLCBhZXMoeCA9IGNvZGUsIHkgPSBkYXRlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcgZXQgZGF0ZXMiKQ0KYGBgDQoNCsOAIHByZW1pw6hyZSB2dWUsIGxhIHZhcmlhYmxlICJkYXRlIiBuJ2V4cGxpcXVlIHBhcyBsYSB2YXJpYWJsZSAiY29kZSIgZHUgVExHLiBMZXMgMjYwMCBwcmVtaWVycyBpZGVudGlmaWFudHMgc2UgY29uY2VudHJlbnQgYXZhbnQgMjUwMCwgZXQgbCdvbiBjb25zdGF0ZSBxdWVscXVlcyAiY2hlbWluw6llcyIgYXV4IGVudmlyb25zIGRlIDMwMDAsIDQwMDAgZXQgOTAwMCBjb25jZXJuYW50IHN1cnRvdXQgbGVzIGF1dGV1cnMgZCdhcHLDqHMgNTAwIENFLg0KDQotLS0NCg0KIyMjIyBBdXRldXJzIGxhdGlucw0KDQpgYGB7ciBwaGktY29kZS1kYXRlfQ0KZ2dwbG90KHBoaV9hdXRob3JzX2RmLCBhZXMoeCA9IGNvZGUsIHkgPSBkYXRlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBQSEkgZXQgZGF0ZXMiKQ0KYGBgDQoNCkNvbmNlcm5hbnQgbGVzIGF1dGV1cnMgbGF0aW5zLCBvbiBzZW1ibGUgYXBlcmNldm9pciBwb3VyIGxlIGNvZGUgUEhJIHVuZSBjb3Jyw6lsYXRpb24gYXNzZXogZm9ydGUgZW50cmUgbGEgcHJvZ3Jlc3Npb24gZGVzIGlkZW50aWZpYW50cyBldCBjZWxsZSBkZXMgZGF0ZXMuIFVuIGlkZW50aWZpYW50IGN1bG1pbmUgw6AgOTUwMCBldCB0cm9pcyBhdXRyZXMgYXV0ZXVycyBkw6lwYXNzYW50IDkwMDAgbmUgc29udCBwYXMgZGF0w6lzLg0KDQpgYGB7cn0NCmNvci50ZXN0KHBoaV9hdXRob3JzX2RmJGNvZGUsIHBoaV9hdXRob3JzX2RmJGRhdGUpDQpgYGANCg0KQ2V0dGUgY29ycsOpbGF0aW9uIGVudHJlIGNlcyBkZXV4IHZhcmlhYmxlcywgaWRlbnRpZmlhbnQgZXQgZGF0ZSwgcGFyYcOudCBzdGF0aXN0aXF1ZW1lbnQgdsOpcmlmacOpZS4NCg0KUmVnYXJkb25zIGRlIHBsdXMgcHLDqHMgbGEgc8OpcXVlbmNlIGRlIDAgw6AgMzAwMC4NCg0KYGBge3J9DQp0bXBfcGhpXzMwMDAgPC0NCiAgcGhpX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgMzAwMCkNCmBgYA0KDQpgYGB7cn0NCmNvci50ZXN0KHRtcF9waGlfMzAwMCRjb2RlLCB0bXBfcGhpXzMwMDAkZGF0ZSkNCmBgYA0KDQpMYSBjb3Jyw6lsYXRpb24gcGFyYcOudCBlbmNvcmUgcGx1cyBmb3J0ZSBwb3VyIGxlcyBpZGVudGlmaWFudHMgaW5mw6lyaWV1cnMgw6AgMzAwMC4gRXNzYXlvbnMgZGUgbW9kw6lsaXNlciB1bmUgcmVsYXRpb24gbGluw6lhaXJlLg0KDQpgYGB7cn0NCiMnIE1ha2UgYSBsaW5lYXIgbW9kZWwsIHByaW50IGl0cyBpbmZvcyBhbmQgY29tcG9uZW50cywgYW5kIHBsb3QgaXRzIGVxdWl2YWxlbnQuDQojJyBycTogSGVyZSB3ZSB1c2UgYHRpYmJsZSgpYCwgdG8gbWFrZSBxdW9zdXJlcyB3b3JrLg0KIycgVGhlcmUgbWF5IGJlIGEgbmVhdGVyIHdheS4NCiMnIHJxOiBXZSBuZWVkIHRvIGV4cGxpY2l0bHkgcmV0dXJuIHRoaW5ncyB0byBiZSBwcmludGVkLA0KIycgb3RoZXJ3aXNlIG9ubHkgYSB0YWJsZSBhdCB0aGUgZW5kIG9mIHRoZSBmdW5jdGlvbiB3aWxsIGJlIHByaW50ZWQuDQojJyBUaHVzLCB3ZSB0aGVuIG5lZWQgdG8gJ2hpZGUnIGNodW5rIHJlc3VsdHMgdG8gYXZvaWQgcHJpbnRpbmcgb2YgcmF3IGNvbnNvbGUgb3V0cHV0Lg0KIycgQHNlZSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MjAyNDkyMS93aHktZG9lcy1rYWJsZS1ub3QtcHJpbnQtd2hlbi11c2VkLXdpdGhpbi1hLWZ1bmN0aW9uLWluLXJtYXJrZG93bg0KIycgQHBhcmFtIHZhciBTdHJpbmcgb2YgdGhlIHZhcmlhYmxlIG5hbWUgdG8gdGVzdCBpbiB0aGUgbGluZWFyIG1vZGVsLg0KIycgQHBhcmFtIHZhcl9zdHJpbiBTdHJpbmcgdG8gZGlzcGxheSBpbiB0aGUgcGxvdCBuYW1lLg0KIycgQHJldHVybiBUaGluZ3MgdG8gcHJpbnQuDQpwaGlfZGlzcGxheV9sbSA8LSBmdW5jdGlvbih2YXIsIHZhcl9zdHIpIHsNCiAgZGF0YV9kZiA8LSB0bXBfcGhpXzMwMDANCiAgbG1fZGYgPC0NCiAgICB0aWJibGUoDQogICAgICBsbV9jb21wb25lbnRzID0gYnJvb206OnRpZHkobG0oY29kZSB+ICEhc3ltKHZhciksIGRhdGFfZGYpKSwNCiAgICAgIGxtX2luZm9zID0gYnJvb206OmdsYW5jZShsbShjb2RlIH4gISFzeW0odmFyKSwgZGF0YV9kZikpDQogICAgKQ0KICBsbV9jb21wc19wcmludCA8LSBsbV9kZiAlPiUgcHVsbChsbV9jb21wb25lbnRzKSAlPiUga25pdF9wcmludCgpDQogIGxtX2luZm9zX3ByaW50IDwtIGxtX2RmICU+JSBwdWxsKGxtX2luZm9zKSAlPiUgc2xpY2VfaGVhZCgpICU+JSBrbml0X3ByaW50KCkNCiAgbG1fcGxvdCA8LSBkYXRhX2RmICU+JQ0KICAgIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSAhIXN5bSh2YXIpKSkgKw0KICAgIGdlb21fcG9pbnQoKSArDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cygNCiAgICAgIGxpbWl0cyA9IGMoLTUwMCwgNjAwKSwNCiAgICAgIGJyZWFrcyA9IHNlcSgtNTAwLCA2MDAsIGJ5ID0gMTAwKQ0KICAgICkgKw0KICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoIklkZW50aWZpYW50cyBQSEkgZXQgIix2YXJfc3RyKSkNCiAgcmV0dXJuKGxpc3QoDQogICAgbG1fY29tcHNfcHJpbnQsDQogICAgbG1faW5mb3NfcHJpbnQsDQogICAgbG1fcGxvdA0KICApKQ0KfQ0KYGBgDQoNCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQ0KcGhpX2Rpc3BsYXlfbG0oImRhdGUiLCAiZGF0ZXMgZCdhY3Rpdml0w6kiKQ0KYGBgDQoNCkVuIHkgcmVnYXJkYW50IGRlIHBsdXMgcHLDqHMgb24gdm9pdCBiaWVuLCBzdXIgbGVzIGlkZW50aWZpYW50cyBlbnRyZSAwIGV0IDMwMDAsIHVuZSBjb3Jyw6lsYXRpb24gbGluw6lhaXJlIHNpZ25pZmljYXRpdmUgc2FucyBhbWJpZ3XDr3TDqSAoJHBcbWJveHstfXZhbGV1ciBcbGxsIDAuMDAxJCkgZW50cmUgbGEgdmFsZXVyIGRlIGwnaWRlbnRpZmlhbnQgZXQgbGEgZGF0ZSwgb3UgbGUgc2nDqGNsZSwgZCdhY3Rpdml0w6nCoDogdW4gc2ltcGxlIG1vZMOobGUgbGluw6lhaXJlICgkY29kZV97aX0gPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXHRpbWVzIGRhdGVfe2l9ICsgXGVwc2lsb25fe2l9JCkgZXhwbGlxdWUgYWluc2kgbGVzIHRyb2lzIHF1YXJ0cyBkZSBsYSB2YXJpYW5jZSAoJFJeezJ9IFxhcHByb3ggMC43NiQpLg0KDQpSYXBwZWxvbnMgcXVlIG5vdXMgYXZvbnMgaWNpIHV0aWxpc8OpIHVuZSBzZXVsZSBkZXMgdHJvaXMgZGF0ZXMgcXVpIMOpdGFpZW50IMOgIG5vdHJlIGRpc3Bvc2l0aW9uwqA6IHZveW9ucyBsYSBtYW5pw6hyZSBkb250IHNlIGRpc3RyaWJ1ZW50IGxlcyBkZXV4IGF1dHJlcy4NCg0KYGBge3IsIHJlc3VsdHMgPSAnaGlkZSd9DQpwaGlfZGlzcGxheV9sbSgiZGF0ZV9iZWdpbiIsICJkYXRlcyBkZSBjb21tZW5jZW1lbnQiKQ0KYGBgDQoNCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQ0KcGhpX2Rpc3BsYXlfbG0oImRhdGVfZW5kIiwgImRhdGVzIGRlIGZpbiIpDQpgYGANCg0Kw4AgcGFydGlyIGRlcyBzZXVscyBjYWxjdWxzIHN0YXRpc3RpcXVlcywgaWwgbmUgcGFyYcOudCBwYXMgw6l2aWRlbnQgZGUgdGlyZXIgZGVzIGNvbmNsdXNpb25zLiBFbiByZXZhbmNoZSwgZHUgcG9pbnQgZGUgdnVlIGRlIGwnYW5hbHlzZSBncmFwaGlxdWUsIGxlcyBkYXRlcyBkZSAiZmluIiBzZW1ibGVudCwgYXUgbW9pbnMgYXV0b3VyIGRlIGwnaWRlbnRpZmlhbnQgNTAwLCBmb3JtZXIgdW4gY2FycsOpIGNvbW1lIHNpIGxlcyBhdXRldXJzIG1vcnRzIGF1IGNvdXJzIGR1IHByZW1pZXIgc2nDqGNsZSBhdmFudCBub3RyZSDDqHJlIGZhaXNhaWVudCB0b3VzLCBvdSBwcmVzcXVlLCBwYXJ0aWUgZCd1bmUgbcOqbWUgY2F0w6lnb3JpZS4gT24gcG91cnJhaXQgZW5jb3JlIGFmZmluZXIgbGVzIGFuYWx5c2VzIGRlIGNldHRlIGNhdMOpZ29yaXNhdGlvbiwgc2FucyBvdWJsaWVyIHF1ZSBsZXMgZG9ubsOpZXMgbWFucXVhbnRlcyBzb250IHBsdXMgbm9tYnJldXNlcyBwb3VyIGxlcyBkYXRlcyBkZSAiZmluIiBvdSBkZSAiZMOpYnV0IiBxdWUgbGEgZGF0ZSBwbHVzIGfDqW7DqXJhbGUgZCdhY3Rpdml0w6kgKHZvaXIgbGEgc2VjdGlvbiBbIkRvbm7DqWVzIGZpbmFsZXMiXSgjZG9ubsOpZXMtZmluYWxlcy1vYnRlbnVlcykpLg0KDQpgYGB7cn0NCnJlbW92ZSh0bXBfcGhpXzMwMDApDQpgYGANCg0KIyMjIEFuYWx5c2VzIGVuIHRyb2lzIGRpbWVuc2lvbnMNCg0KRCdhdXRyZXMgdmFyaWFibGVzIGludGVydmllbm5lbnQtZWxsZXMgZGFucyBsYSBudW3DqXJvdGF0aW9uIGRlcyBjb2Rlc8KgPyBFbiBzdXMgZGVzIGRhdGVzLCBub3VzIGFsbG9ucyBleGFtaW5lciB0cm9pcyBhdXRyZXMgdmFyaWFibGVzwqA6IGwnaW5pdGlhbGUgZHUgbm9twqDigJMgZW4gY3JvaXNhbnQgZG9uYyBsYSBxdWVzdGlvbiBkZSBsJ29yZHJlIGFscGhhYsOpdGlxdWUgcXVlIG5vdXMgYXZvbnMgZMOpasOgIMOpdm9xdcOpZSDigJMsIGxlIGdlbnJlIGxpdHTDqXJhaXJlLCBhaW5zaSBxdWUgbGUgbGlldS4gQ2VzIHZhcmlhYmxlcyBzZXJvbnQgZXhwcmltw6llcyBwYXIgZGVzIGNvdWxldXJzLg0KDQpMZXMgY291bGV1cnMgcGFyIGTDqWZhdXQgZGUgZ2dwbG90IMOpdGFudCBwbHV0w7R0IGZhZGVzIGV0IHBldSBkaWZmw6lyZW5jacOpZXMsIHJlbmRhbnQgbGEgbGVjdHVyZSBkaWZmaWNpbGUsIG5vdXMgY3LDqWVyb25zIMOpZ2FsZW1lbnQgdW5lIHBhbGV0dGUgcGFzc2FudCBncmFkdWVsbGVtZW50IGR1IHJvdWdlIGF1IGJsZXUsIGVuIHBhc3NhbnQgcmVzcGVjdGl2ZW1lbnQgcGFyIGwnb3JhbmfDqSwgbGUgamF1bmUgZXQgbGUgdmVydCAoaWwgZmF1dCBjb21wdGVyIHByw6hzIGRlIDI2IGxldHRyZXMpLg0KDQpgYGB7ciBjb2xvcnN9DQojIENyw6lhdGlvbiBkJ3VuZSBwYWxldHRlIGRlIGNvdWxldXJzIGRlIHR5cGUgcm9zYWNlLA0KIyBlbiBqb3VhbnQgc3VyIGxlcyBjb2RlcyAjUlJWVkJCLCBjaGFxdWUgY2hpZmZyZSBkZSAwIMOgIEYuDQpjb3VsZXVycyA8LSBjKA0KICAiIzk5MDAwMCIsICIjY2MwMDAwIiwgIiNmZjAwMDAiLCAiI2ZmMzMwMCIsDQogICIjZmY2NjAwIiwgIiNmZjk5MDAiLCAiI2ZmY2MwMCIsICIjZmZmZjAwIiwNCiAgIiNjY2ZmMDAiLCAiIzk5ZmYwMCIsICIjNjZmZjAwIiwgIiMzM2ZmMDAiLA0KICAiIzAwZmYwMCIsICIjMDBmZjMzIiwgIiMwMGZmNjYiLCAiIzAwZmY5OSIsDQogICIjMDBmZmJiIiwgIiMwMGZmZmYiLCAiIzAwY2NmZiIsICIjMDA5OWZmIiwNCiAgIiMwMDY2ZmYiLCAiIzAwMzNmZiIsICIjMDAwMGZmIiwgIiMwMDAwY2MiLA0KICAiIzAwMDA5OSINCikNCmBgYA0KDQojIyMgMi4zLiBJZGVudGlmaWFudHMsIGRhdGVzIGV0IGluaXRpYWxlcw0KDQpOb3VzIHJlcHJlbm9ucyBsZXMgZGV1eCBncmFwaGlxdWVzIHByw6ljw6lkZW50cyBwcm9qZXRhbnQgbGVzIGlkZW50aWZpYW50cyBzZWxvbiBsZXMgZGF0ZXMgKFRMRyBldCBQSEkpLCBlbiBjb2xvcmFudCBjZXR0ZSBmb2lzIGxlcyBwb2ludHMgc2Vsb24gbGVzIGluaXRpYWxlcyBkZXMgYXV0ZXVycy4NCg0KLS0tDQoNCiMjIyMgQXV0ZXVycyBncmVjcw0KDQpgYGB7ciB0bGctY29kZS1kYXRlLWluaXR9DQpnZ3Bsb3QodGxnX2F1dGhvcnNfZGYsIGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gaW5pdCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRywgZGF0ZXMgZXQgaW5pdGlhbGVzIikNCmBgYA0KDQpEZSBsb25ncyB0cmFpdHMgdmVydGljYXV4IGRlIGNvdWxldXJzIGFwcGFyYWlzc2VudCwgbWFpcyB1biBjYWRyYWdlIGVzdCDDoCByw6lhbGlzZXIsIG5vdGFtbWVudCBwb3VyIGxlcyBjb2RlcyBlbnRyZSAxMTUwIGV0IDE4MDAuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtaW5pdC16b29tfQ0KZ2dwbG90KHRsZ19hdXRob3JzX2RmLCBhZXMoeCA9IGNvZGUsIHkgPSBkYXRlLCBjb2xvciA9IGluaXQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHhsaW0oMTE1MCwgMTgwMCkgKw0KICB5bGltKC03NTAsIDUwMCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY291bGV1cnMpICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBkYXRlcyBldCBpbml0aWFsZXMgKDExNTAtMTgwMCkiKQ0KYGBgDQoNCklsIGFwcGFyYcOudCBjbGFpcmVtZW50IHF1ZSBsZXMgbnVtw6lyb3MgZGUgY29kZSBlbnRyZSAxMTUwIGV0IDE4MDAgc3VpdmVudCBsZXMgaW5pdGlhbGVzIGR1IG5vbXMgZGVzIGF1dGV1cnMgZ3JlY3MuIExlIGdyYXBoaXF1ZSBzdWl2YW50IGV4YW1pbmUgbGVzIGNvZGVzIGVudHJlIDE4MDAgZXQgMjUwMC4gRW4gcmV2YW5jaGUsIGxhIGRhdGUgcGFyYcOudCBuZSBqb3VlciBhdWN1bmUgaW1wb3J0YW5jZcKgOiBvbiByZXRyb3V2ZSwgcG91ciBjaGFxdWUgbcOqbWUgZGF0ZSwgZGVzIGF1dGV1cnMgdG91dCBsZSBsb25nIGRlIGxhIHPDqXF1ZW5jZSBkJ2lkZW50aWZpYW50cyBjb25zaWTDqXLDqWUuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtaW5pdC16b29tLTJ9DQpnZ3Bsb3QodGxnX2F1dGhvcnNfZGYsIGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gaW5pdCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgxODAwLCAyNTAwKSArDQogIHlsaW0oLTc1MCwgNTAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVycykgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIGRhdGVzIGV0IGluaXRpYWxlcyAoMTgwMC0yNTAwKSIpDQpgYGANCg0KTCdvYnNlcnZhdGlvbiBxdWkgcydhcHBsaXF1ZSBlbnRyZSAxMTUwIGV0IDE4MDAgbmUgc2UgcmV0cm91dmUgcGFzIGVudHJlIDE4MDAgZXQgMjUwMCwgbcOqbWUgc2kgbCdvbiByZXRyb3V2ZSBxdWVscXVlcyBsaWduZXMgYXNjZW5kYW50ZXMsIHBldXQtw6p0cmUgZm9ydHVpdGVzLg0KDQpPYnNlcnZvbnMgZMOpc29ybWFpcyBsZXMgYXV0cmVzIHPDqXF1ZW5jZXMgcXVlIG5vdXMgYXZpb25zIGRpc3Rpbmd1w6llcyBsb3JzcXVlIG5vdXMgYXZvbnMgcHJvamV0w6kgbGVzIGlkZW50aWZpYW50cyBlbiBmb25jdGlvbiBkZXMgbm9tcy4NCg0KYGBge3IgdGxnLWNvZGUtZGF0ZS1pbml0LXNlcXN9DQojJyBQbG90IGNvZGUgYnkgZGF0ZSBhbmQgaW5pdCwNCiMnIGZvciBhIHNlcXVlbmNlIGJldHdlZW4gdHdvIGdpdmVuIHZhbHVlcywNCiMnIGZyb20gYHBoaV9hdXRob3JzX2RmX25vcHJgLg0KIycgQHBhcmFtIHN0YXJ0IE51bWJlci4gQ29kZSB0byBzdGFydCB3aXRoDQojJyBAcGFyYW0gZW5kIE51bWJlci4gQ29kZSB0byBlbmQgd2l0aC4NCnRsZ19wbG90X2NvZGVfZGF0ZV9pbml0X3NlcSA8LSBmdW5jdGlvbihzdGFydCwgZW5kKSB7DQogIHRsZ19hdXRob3JzX2RmICU+JQ0KICAgIGZpbHRlcihjb2RlID49IHN0YXJ0LCBjb2RlIDw9IGVuZCkgJT4lDQogICAgZHJvcF9uYShkYXRlLCBpbml0KSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBpbml0KSkgKw0KICAgIGdlb21fcG9pbnQoKSArDQogICAgI3lsaW0oLTYwMCwgMzAwKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlMCgiSWRlbnRpZmlhbnRzIFRMRywgZGF0ZXMgZXQgaW5pdGlhbGVzICgiLHN0YXJ0LCItIixlbmQsIikiKSkNCn0NCmBgYA0KDQpgYGB7cn0NCnRsZ19wbG90X2NvZGVfZGF0ZV9pbml0X3NlcSgxMDAsIDIwMCkNCnRsZ19wbG90X2NvZGVfZGF0ZV9pbml0X3NlcSgzOTAsIDU1MCkNCnRsZ19wbG90X2NvZGVfZGF0ZV9pbml0X3NlcSg2NTAsIDc1MCkNCnRsZ19wbG90X2NvZGVfZGF0ZV9pbml0X3NlcSg3NTAsIDExMDApDQpgYGANCg0KQ29tbWUgbm91cyBsJ2F2aW9ucyByZW1hcnF1w6ksIGlsIGV4aXN0ZSBlbiBlZmZldCB1bmUgcsOpZ3VsYXJpdMOpLiBOw6lhbm1vaW5zLCBsZXMgZGF0ZXMgbmUgc2VtYmxlbnQgam91ZXIgYXVjdW4gcsO0bGUgc3VyIGNlcyBzw6lxdWVuY2VzLCBzaSBjZSBuJ2VzdCBxdWUgY2hhcXVlIHPDqXF1ZW5jZSBzJ8OpdGFsZSBwbHVzIG91IG1vaW5zIGRhbnMgbGUgdGVtcHPCoDoNCg0KLSBsYSBzw6lxdWVuY2UgZW50cmUgMTAwIGV0IDIwMCBzJ8OpdGFsZSBkZSAtNDAwIMOgIDI1MA0KLSBsYSBzw6lxdWVuY2UgZW50cmUgNDAwIGV0IDUyNSBzJ8OpdGFsZSBkZSAtNTAwIMOgIC0yMDAgKGMnZXN0IHBhcnRpY3VsacOocmVtZW50IHJhbWFzc8OpKQ0KLSBsYSBzw6lxdWVuY2UgZW50cmUgNjUwIGV0IDc1MCBzJ8OpdGFsZSBkZSAtNTAwIMOgIDU1MA0KLSBsYSBzw6lxdWVuY2UgZW50cmUgNzUwIGV0IDExMDAgcyfDqXRhbGUgZGUgLTUwMCDDoCAyNTANCi0gbGEgc8OpcXVlbmNlIGVudHJlIDExNTAgZXQgMTgwMCBzJ8OpdGFsZSBkZSAtNzAwIMOgIDUwMCAoYydlc3QgcGFydGljdWxpw6hyZW1lbnQgw6l0ZW5kdSkNCg0KLS0tDQoNCiMjIyMgQXV0ZXVycyBsYXRpbnMNCg0KT24gYXBwbGlxdWUgbGUgcHJpbmNpcGUgZGVzIHBvaW50cyBkZSBjb3VsZXVyIHNlbG9uIGwnaW5pdGlhbGUgcG91ciBsZXMgYXV0ZXVycyBsYXRpbnMuDQoNCmBgYHtyIHBoaS1jb2RlLWRhdGUtaW5pdH0NCiMgQXV0ZXVycyBsYXRpbnMuDQpnZ3Bsb3QocGhpX2F1dGhvcnNfZGYsIGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gaW5pdCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgwLCAyNTAwKSArDQogIHlsaW0oLTM1MCwgNjAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVycykgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBQSEksIGRhdGVzIGV0IGluaXRpYWxlcyIpDQpgYGANCg0KU2kgbGUgY29kZSBlc3QgY29ycsOpbMOpIMOgIGxhIGRhdGUsIGNlIHF1aSBhcHBhcmFpc3NhaXQgZMOpasOgIHBsdXMgaGF1dCwgbGUgbm9tIG5lIHNlbWJsZSBhdm9pciBhdWN1biByw7RsZSBkYW5zIGxhIG51bcOpcm90YXRpb24uDQoNCklsIG5vdXMgYXZhaXQgbsOpYW5tb2lucyBzZW1ibMOpIHF1ZSBxdWVscXVlIGNob3NlIGNvbW1lIHVuZSBzdWl0ZSBhbHBoYWLDqXRpcXVlIHBvdXJyYWl0IGJpZW4gYXBwYXJhw650cmUgYXUgbW9pbnMgZW50cmUgbGVzIGlkZW50aWZpYW50cyA0MDAgZXQgNzAwLiBSZXN0cmVpZ25vbnMgZG9uYyBsJ29ic2VydmF0aW9uIHBsdXMgc3DDqWNpZmlxdWVtZW50IMOgIGNldHRlIHPDqXF1ZW5jZS4gw4l0YW50IGRvbm7DqSBxdWUgY2V0dGUgc8OpcXVlbmNlIGZhaXQgYXBwYXJhw650cmUgZGVzIGF1dGV1cnMgZCd1bmUgcMOpcmlvZGUgc2ltaWxhaXJlwqDigJMgbGUgcHJlbWllciBzacOoY2xlIGF2YW50IG5vdHJlIMOocmXCoOKAkywgbm91cyBhbGxvbnMgcG91ciB1biBpbnN0YW50IHJldmVuaXIgZW4gZGV1eCBkaW1lbnNpb25zIGVuIHN1cHByaW1hbnQgbGEgdmFyaWFibGUgZGF0ZSBldCBhaW5zaSBtaWV1eCB2b2lyIGxhIHLDqXBhcnRpdGlvbiBkZXMgbm9tcy4NCg0KYGBge3IgcGhpLWNvZGUtaW5pdC00MDAtNzUwfQ0KZ2dwbG90KHBoaV9hdXRob3JzX2RmLCBhZXMoeCA9IGNvZGUsIHkgPSBmY3RfcmVvcmRlcihuYW1lLCBkZXNjKG5hbWUpKSwgY29sb3IgPSBpbml0KSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDQwMCwgNzUwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVycykgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBQSEkgZXQgbm9tcyAoNDAwLTc1MCkiLCB4ID0gImNvZGUiLCB5ID0gIm5hbWUiKQ0KYGBgDQoNClVuZSBsaWduZSBwYXJhw650IHZhZ3VlbWVudCBzZSBkaXN0aW5ndWVyLCBtYWlzIGRlIHRyw6hzIG5vbWJyZXV4IGF1dGV1cnMgc2VtYmxlbnQgbmUgcGFzIGVudHJlciBkYW5zIGNldHRlIGxvZ2lxdWUuIEMnZXN0IHBvc3NpYmxlIGNhciBsZSBub20gcXVpIGFwcGFyYcOudCBkYW5zIG5vdHJlIHRhYmxlYXUgbidlc3QgcGFzIGNvbmZvcm1lIGF1IG5vbSB1dGlsaXPDqSBkYW5zIGxhIGNsYXNzaWZpY2F0aW9uLg0KDQpPbiByZW1hcnF1ZSBlbiBlZmZldCBxdWUgbGVzIG5vbXMgdGVscyBxdWUgbm91cyBsZXMgYXZvbnMgcsOpY3Vww6lyw6lzIGNvbW1lbmNlbnQgc291dmVudCBwYXIgbGUgIipwcmFlbm9tZW4qIi4gSWwgZXN0IGZhY2lsZSBkJ8O0dGVyIGxlcyBwcsOpbm9tcyByZXByw6lzZW50w6lzIHBhciB1bmUgaW5pdGlhbGUgc3VpdmllIGQndW4gcG9pbnQuIE9uIGNyw6llIHBvdXIgY2VsYSB1biB0YWJsZWF1IGludGVybcOpZGlhaXJlLg0KDQpgYGB7cn0NCnBoaV9hdXRob3JzX2RmX25vcHIgPC0gcGhpX2F1dGhvcnNfZGYNCnBoaV9hdXRob3JzX2RmX25vcHIkbmFtZSA8LSBnc3ViKCJbQS1aXVthLXpdezAsMn1cXC4gIiwgIiIsIHBoaV9hdXRob3JzX2RmX25vcHIkbmFtZSkNCnBoaV9hdXRob3JzX2RmX25vcHIkaW5pdCA8LSBzdWJzdHJpbmcocGhpX2F1dGhvcnNfZGZfbm9wciRuYW1lLDEsMSkNCmBgYA0KDQpVbiB0cmF2YWlsIHBsdXMgc3lzdMOpbWF0aXF1ZSBhdXJhaXQgY29uc2lzdMOpIMOgIG9ic2VydmVyIHN1ciBsZSBbc2l0ZSBkZSBQSEldKGh0dHBzOi8vbGF0aW4ucGFja2h1bS5vcmcvYnJvd3NlKSBjZSBxdWkgeSBlc3QgY29uc2lkw6lyw6kgY29tbWUgw6l0YW50IGxlIG5vbSBwcmluY2lwYWwgZGUgY2hhcXVlIGF1dGV1ciAoYXBwYXJhaXNzYW50IGVuIGdyYXMpIHBvdXIgZ2FyZGVyIGNlbHVpLWNpIGNvbW1lIG5vbSBkZSByw6lmw6lyZW5jZS4gSWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlIGRlIHLDqWN1cMOpcmVyIGNlcyBkb25uw6llcyBkZXB1aXMgaW50ZXJuZXQgcGFyIGV4ZW1wbGUgYXZlYyBsYSBiaWJsaW90aMOocXVlIGBydmVzdGAuDQoNClBvdXIgbCdoZXVyZSwgbm91cyBub3VzIGNvbnRlbnRlcm9ucyBkZSBjZXR0ZSBwcmVtacOocmUgbWlzZSBlbiBmb3JtZS4NCg0KYGBge3J9DQpnZ3Bsb3QocGhpX2F1dGhvcnNfZGZfbm9wciwgYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBpbml0KSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDAsIDI1MDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFBISSwgZGF0ZXMgZXQgaW5pdGlhbGVzIChzYW5zIHByYWVub21lbikiKQ0KYGBgDQoNCklsIGVzdCBkaWZmaWNpbGUgZGUgZGlzdGluZ3VlciBsZXMgY2hvc2VzIMOgIGNlIG5pdmVhdS4gRGUgbm91dmVhdSwgcmV2ZW5vbnMgw6AgdW5lIHJlcHLDqXNlbnRhdGlvbiBlbiBkZXV4IGRpbWVuc2lvbnMgZW4gc3VwcHJpbWFudCBsYSB2YXJpYWJsZSAiZGF0ZSIsIHB1aXMgbm91cyBub3VzIGZvY2FsaXNlcm9ucyBzdXIgY2VydGFpbmVzIHPDqXF1ZW5jZXMsIGNoYWN1bmUgY29ycmVzcG9uZGFudCDDoCB1bmUgcMOpcmlvZGUuDQoNCmBgYHtyfQ0KcGhpX2F1dGhvcnNfZGZfbm9wciAlPiUNCiAgZmlsdGVyKGNvZGUgPCAyNTAwKSAlPiUNCiAgZHJvcF9uYShuYW1lLCBpbml0KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpLCBjb2xvciA9IGluaXQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVycykgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBQSEkgZXQgbm9tcyAoc2FucyBwcmFlbm9tZW4pIiwgeCA9ICJjb2RlIiwgeSA9ICJuYW1lIikNCg0KDQpgYGANCg0KRGVzIGxpZ25lcyBhcHBhcmFpc3NlbnQgZWZmZWN0aXZlbWVudCBiaWVuIGNsYWlyZW1lbnTCoCEgUmVnYXJkb25zIGxlcyBzw6lxdWVuY2VzIGRlIHBsdXMgcHLDqHMuDQoNCmBgYHtyfQ0KIycgUGxvdCBjb2RlIGJ5IG5hbWUsDQojJyBmb3IgYSBzZXF1ZW5jZSBiZXR3ZWVuIHR3byBnaXZlbiB2YWx1ZXMsDQojJyBmcm9tIGBwaGlfYXV0aG9yc19kZl9ub3ByYC4NCiMnIEBwYXJhbSBzdGFydCBOdW1iZXIuIENvZGUgdG8gc3RhcnQgd2l0aA0KIycgQHBhcmFtIGVuZCBOdW1iZXIuIENvZGUgdG8gZW5kIHdpdGguDQpwaGlfcGxvdF9jb2RlX25hbWVfc2VxIDwtIGZ1bmN0aW9uKHN0YXJ0LCBlbmQpIHsNCiAgcGhpX2F1dGhvcnNfZGZfbm9wciAlPiUNCiAgICBmaWx0ZXIoY29kZSA+PSBzdGFydCwgY29kZSA8PSBlbmQpICU+JQ0KICAgIGRyb3BfbmEobmFtZSwgaW5pdCkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpLCBjb2xvciA9IGluaXQpKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY291bGV1cnMpICsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSBwYXN0ZTAoIklkZW50aWZpYW50cyBQSEkgZXQgbm9tcyAoc2FucyBwcmFlbm9tZW4sICIsc3RhcnQsIi0iLGVuZCwiKSIpLA0KICAgICAgeCA9ICJjb2RlIiwNCiAgICAgIHkgPSAibmFtZSINCiAgICApICsNCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkNCn0NCmBgYA0KDQpgYGB7cn0NCnBoaV9wbG90X2NvZGVfbmFtZV9zZXEoMCwgMjAwKQ0KcGhpX3Bsb3RfY29kZV9uYW1lX3NlcSg0MDAsIDc1MCkNCnBoaV9wbG90X2NvZGVfbmFtZV9zZXEoNzUwLCAxMjAwKQ0KcGhpX3Bsb3RfY29kZV9uYW1lX3NlcSgxMjAwLCAxNDAwKQ0KYGBgDQoNCkxlcyB0ZW5kYW5jZXMgYXBwYXJhaXNzZW50IGJpZW4gYXZlYyBjbGFydMOpLg0KDQpVbmUgZGVybmnDqHJlIG1hbmnDqHJlIGRlIHJlcHLDqXNlbnRlciBjZXMgdGVuZGFuY2VzIHNlcmFpdCBkZSBjb2xvcmVyIGNldHRlIGZvaXMgbm9uIHBsdXMgbGVzIGluaXRpYWxlcyBtYWlzIGxlcyBkYXRlc8KgOiBvbiBkZXZyYWl0IG9ic2VydmVyIHF1ZSBsZXMgZGlmZsOpcmVudGVzIHPDqXF1ZW5jZXMgc29udCBjaGFjdW5lIGQndW5lIHRlaW50ZSBwYXJ0aWN1bGnDqHJlLg0KDQpgYGB7cn0NCnBoaV9hdXRob3JzX2RmX25vcHIgJT4lDQogIGZpbHRlcihjb2RlIDwgMjUwMCkgJT4lDQogIGRyb3BfbmEobmFtZSwgZGF0ZSkgJT4lDQogIGdncGxvdChhZXMoY29kZSwgZmN0X3Jlb3JkZXIobmFtZSwgZGVzYyhuYW1lKSksIGNvbG9yID0gZGF0ZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgUEhJLCBub21zIGV0IGRhdGVzIiwgeSA9ICJuYW1lIikgKw0KICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gY291bGV1cnMpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KQydlc3QgZWZmZWN0aXZlbWVudCBjZSBxdWUgbCdvbiBvYnNlcnZlwqAhDQoNCklsIHNlbWJsZXJhaXQgZG9uYyBxdWUgbGVzIGF1dGV1cnMgbGF0aW5zIHNvaWVudCwgZGFucyBsYSBjbGFzc2lmaWNhdGlvbiBQSEksIHJhbmfDqXMgZCdhYm9yZCBwYXIgZGF0ZSwgZXQgZW5zdWl0ZSBkZSBtYW5pw6hyZSBzZWNvbmRhaXJlLCBzdXIgY2hhcXVlIHDDqXJpb2RlLCBwYXIgb3JkcmUgYWxwaGFiw6l0aXF1ZSBkdSBub20uDQoNCkxlICoqbm9tKiogbmUgY29tbWVuY2UgYWxvcnMgbWFuaWZlc3RlbWVudCBwYXMgcGFyIGxlICpwcmFlbm9tZW4qLiBMZXMgcG9pbnRzIGFiZXJyYW50cyBwYXIgcmFwcG9ydCBhdXggZHJvaXRlcyBxdWkgc2UgZGVzc2luZW50IHNvbnQgdnJhaXNlbWJsYWJsZW1lbnQgZGVzIGF1dGV1cnMgcG91ciBsZXNxdWVscyBsZSBub20gcXVlIG5vdXMgYXZvbnMgZGFucyBub3RyZSB0YWJsZWF1IG5lIGNvcnJlc3BvbmQgcGFzIGF1IG5vbSB1dGlsaXPDqSBsb3JzIGRlIGwnYXR0cmlidXRpb24gZGUgbCdpZGVudGlmaWFudC4NCg0KUG91ciBkaXN0aW5ndWVyIHBsdXMgY2xhaXJlbWVudCBsZXMgKipww6lyaW9kZXMqKiwgbm91cyBkZXZyaW9ucyBmYWlyZSBkZXMgcmVjaGVyY2hlcyBzdXBwbMOpbWVudGFpcmVzLCBhZmluIGRlIHNhdm9pciBwcsOpY2lzw6ltZW50IHNlbG9uIHF1ZWwocykgY3JpdMOocmUocykgY2VydGFpbnMgYXV0ZXVycyBzb250IHJhdHRhY2jDqXMgw6AgdW5lIHDDqXJpb2RlIGV0IG5vbiDDoCBsYSBwcsOpY8OpZGVudGUgb3Ugw6AgbGEgc3VpdmFudGXCoDogcydhZ2l0LWlsIGR1IHNpw6hjbGUgY29ycmVzcG9uZGFudCDDoCBsYSBkYXRlIGRlIG5haXNzYW5jZcKgPyDDoCBsYSBkYXRlIGRlIG1vcnTCoD8gw6AgbGEgcMOpcmlvZGUgcHJpbmNpcGFsZSBkZSBwcm9kdWN0aW9uIGxpdHTDqXJhaXJlwqA/IE91IGVzdC1jZSB1biBkw6ljb3VwYWdlIGQndW4gYXV0cmUgb3JkcmUsIHNlbG9uIGRlcyBww6lyaW9kZXMgaGlzdG9yaXF1ZXPCoD8gSWwgZmF1ZHJhaXQgcG91ciBjZWxhIGTDqWxpbWl0ZXIgcHLDqWNpc8OpbWVudCBsZXMgc8OpcXVlbmNlc8Kg4oCTIGNlY2kgZmFpdCwgb24gcG91cnJhaXQgcydpbnTDqXJlc3NlciBhdXggYXV0ZXVycyBzaXR1w6lzIMOgIGxldXJzIGV4dHLDqW1pdMOpcywgYWZpbiBkZSBzYWlzaXIgY2UgcXVpIGZhaXQgcGFzc2VyIGQndW5lIHPDqXF1ZW5jZSDDoCB1bmUgYXV0cmUuIExhIHByZW1pw6hyZSBhbmFseXNlIGNvbmR1aXRlIGRhbnMgbGEgc2VjdGlvbiBbIkxlcyBpZGVudGlmaWFudHMgcGFyIGxlcyBkYXRlcyJdKCNsZXMtaWRlbnRpZmlhbnRzLXBhci1sZXMtZGF0ZXMpIGluY2l0ZXJhaXQgw6Agbm91cyBwZW5jaGVyIHN1ciBsZSBzacOoY2xlIGRlIGxhIGRhdGUgZGUgbW9ydC4NCg0KSWwgZmF1dCBlbmZpbiBub3RlciBxdWUsIGNvbW1lIG5vdXMgbCdhdm9ucyBkw6lqw6AgcmVsZXbDqSBwb3VyIGxlcyBhdXRldXJzIGdyZWNzICh2b2lyIGxhIHNlY3Rpb24gWyJMZXMgaWRlbnRpZmlhbnRzIHBhciBsZXMgbm9tcyJdKCNsZXMtaWRlbnRpZmlhbnRzLXBhci1sZXMtbm9tcykpLCBpbCBleGlzdGUgZGUgbm91dmVhdSBkZXMgIioqdHJvdXMqKiIgZGFucyBsZXMgc8OpcXVlbmNlc8KgOyBjZXMgInNhdXRzIiBkYW5zIGxhIG51bcOpcm90YXRpb24gZGVtZXVyZW50IGRpZmZpY2lsZXMgw6Agw6lsdWNpZGVyIGF2ZWMgbGVzIHNldWxlcyBkb25uw6llcyBpY2kgw6Agbm90cmUgZGlzcG9zaXRpb24uDQoNCiMjIyAyLjQuIElkZW50aWZpYW50cyBldCBnZW5yZXMNCg0KUG91ciBsZXMgYXV0ZXVycyBncmVjcywgbGEgbG9naXF1ZSBkZSBjbGFzc2lmaWNhdGlvbiBub3VzIGRlbWV1cmUgcGV1IGNsYWlyZS4gU2kgY2VydGFpbmVzIHPDqXJpZXMgYWxwaGFiw6l0aXF1ZXMgYXBwYXJhaXNzZW50LCBvbiBuZSBzYWl0IHBhcyBwb3VycXVvaSBlbGxlcyBhcHBhcmFpc3NlbnQgZGFucyBjZXQgb3JkcmUtbMOgLCBldCBpbCBleGlzdGUgw6lnYWxlbWVudCBkZXMgc8OpcXVlbmNlcyBlbnRpw6hyZXMgcXVpIHNlbWJsZW50IG5lIHBhcyBjb3JyZXNwb25kcmUgw6AgbCdvcmRyZSBhbHBoYWLDqXRpcXVlIG5pIMOgIGwnb3JkcmUgY2hyb25vbG9naXF1ZS4NCg0KRXNzYXlvbnMgZG9uYyBkZSBjaGVyY2hlciB1bmUgbG9naXF1ZSwgb3UgZGVzIGxvZ2lxdWVzLCDDoCBwYXJ0aXIgZGVzIGdlbnJlcyBsaXR0w6lyYWlyZXMuDQoNCmBgYHtyfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgNTAwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSBmY3RfcmVvcmRlcihnZW5yZSwgZGVzYyhnZW5yZSkpKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcgZXQgZ2VucmVzIGxpdHTDqXJhaXJlcyIsIHkgPSAiZ2VucmUiKQ0KYGBgDQoNClVuIHByZW1pZXIgZ3JhcGhpcXVlIGVuIGRldXggZGltZW5zaW9ucyBuZSBkb25uZSBwYXMgZ3JhbmQtY2hvc2XCoDogw6AgcHJlbWnDqHJlIHZ1ZSwgY2hhcXVlIGdlbnJlIHBldXQgc2UgcsOpcGFydGlyIHRvdXQgZHUgbG9uZyBkZSBsYSBudW3DqXJvdGF0aW9uLg0KDQpTdXBwcmltb25zIGxlcyBnZW5yZXMgY29udGVuYW50IG1vaW5zIGRlIGRpeCBhdXRldXJzIHBvdXIgeSB2b2lyIHBsdXMgY2xhaXIuDQoNCmBgYHtyfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgNTAwMCkgJT4lDQogIGdyb3VwX2J5KGdlbnJlKSAlPiUNCiAgbXV0YXRlKGdlbnJlX24gPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcihnZW5yZV9uID4gMTApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZmN0X3Jlb3JkZXIoZ2VucmUsIGRlc2MoZ2VucmUpKSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHIGV0IGdlbnJlcyBsaXR0w6lyYWlyZXMgKHBsdXMgZGUgZGl4IGF1dGV1cnMpIiwgeSA9ICJnZW5yZSIpDQpgYGANCg0Kw4AgbGEgcmlndWV1ciwgb24gcGV1dCByZWxldmVyIHF1ZSBsZXMgb3JhdGV1cnMgc29udCBjb25jZW50csOpcyBhdSBkw6lidXQgZGUgbGEgbnVtw6lyb3RhdGlvbiwgZXQgbGVzICIqUG9ldGFlKiIgYXV0b3VyIGRlIDI2MDAuDQoNCk7DqWFubW9pbnMsIG9uIGEgc3VyIGNlIGdyYXBoaXF1ZSBkdSBtYWwgw6AgZGlzdGluZ3VlciBsYSBkZW5zaXTDqSBkZXMgaWRlbnRpZmlhbnRzIGV0IGxldXJzIHJlZ3JvdXBlbWVudHMuIFBhciBleGVtcGxlLCBvbiBhIGR1IG1hbCDDoCBmYWlyZSBsYSBkaWZmw6lyZW5jZSBlbnRyZSBsZXMgcGV0aXRlcyBtYXNzZXMgdHLDqHMgZGVuc2VzIGV0IGxlcyBwb2ludHMgdW5pcXVlcyBvdSBwcmVzcXVlLCBldCBvbiBwZWluZSDDoCBhcHByw6loZW5kZXIgw6AgcXVlbCBwb2ludCBjZXJ0YWluZXMgbGlnbmVzIHNvbnQgY29udGludWVzIG91IG5vbi4gQWp1c3RvbnMgbGVzIHBhcmFtw6h0cmVzIGdyYXBoaXF1ZXMgcG91ciBkaXNjZXJuZXIgbGVzIGNob3NlcyBwbHVzIGZhY2lsZW1lbnQuDQoNCmBgYHtyfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlIDwgNTAwMCkgJT4lDQogIGdyb3VwX2J5KGdlbnJlKSAlPiUNCiAgbXV0YXRlKGdlbnJlX24gPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcihnZW5yZV9uID4gMTApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZmN0X3Jlb3JkZXIoZ2VucmUsIGRlc2MoZ2VucmUpKSkpICsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjIsIHNoYXBlID0gMTYsIHdpZHRoID0gMCwgaGVpZ2h0ID0gMC4yKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBnZW5yZXMgbGl0dMOpcmFpcmVzIChwbHVzIGRlIGRpeCBhdXRldXJzKSIsIHkgPSAiZ2VucmUiKQ0KYGBgDQoNCkTDqXNvcm1haXMsIGxlIGdyYXBoaXF1ZSBlc3QgYmllbiBwbHVzIGxpc2libGXCoDogb24gb2JzZXJ2ZSBkZXMgYWpvdXRzICJwYXIgZ3JhcHBlIiwgZW4gcGFydGljdWxpZXIgcG91ciBsZXMgIipDb21pY2kqIiwgIipUcmFnaWNpKiIsICIqRWxlZ2lhY2kqIiwgZXQgw6lnYWxlbWVudCBwb3VyIGxlcyAiKkdlb2dyYXBoaSoiLCAiKkx5cmljaS8tYWUqIiwgIipNZWRpY2kqIiwgIipPcmF0b3JlcyoiLCAiKlBvZXRhZSoiLCAiKlJoZXRvcmljaSoiLCAuLi4NCg0KSmV0b25zIMOpZ2FsZW1lbnQgdW4gxZNpbCBhdXggZ2VucmVzIG1pcyBkZSBjw7R0w6ksIMOgIHNhdm9pciBjZXV4IHF1aSBjb250aWVubmVudCBkaXggYXV0ZXVycyBvdSBtb2lucy4NCg0KYGBge3J9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKGNvZGUgPCA1MDAwKSAlPiUNCiAgZ3JvdXBfYnkoZ2VucmUpICU+JQ0KICBtdXRhdGUoZ2VucmVfbiA9IG4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZmlsdGVyKGdlbnJlX24gPD0gMTApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZmN0X3Jlb3JkZXIoZ2VucmUsIGRlc2MoZ2VucmUpKSkpICsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjMsIHNoYXBlID0gMTYsIHdpZHRoID0gMCwgaGVpZ2h0ID0gMC4xKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBnZW5yZXMgbGl0dMOpcmFpcmVzIChkaXggYXV0ZXVycyBldCBtb2lucykiLCB5ID0gImdlbnJlIikNCmBgYA0KDQpPbiBvYnNlcnZlIGRlcyBwZXRpdHMgcmVncm91cGVtZW50cywgcXVpIG5lIHNvbnQgcGFzIHN5c3TDqW1hdGlxdWVzwqA6IGRlcyAiKlBhcmFkb3hvZ3JhcGhpKiIgc3VydG91dCwgZGVzICIqQnVjb2xpY2kqIiDDqWdhbGVtZW50LCBkZXMgIipEb3hvZ3JhcGhpKiIsIHBldXQtw6p0cmUgYXVzc2kgZGVzICIqTXl0aG9ncmFwaGkqIi4uLg0KDQpFc3NheW9ucyBkw6lzb3JtYWlzIGRlcyBhbmFseXNlcyBlbiB0cm9pcyBkaW1lbnNpb25zLCBlbiBjb3VsZXVycy4NCg0KYGBge3J9DQpsZW5ndGgodW5pcXVlKHRsZ19hdXRob3JzX2RmJGdlbnJlKSkNCmBgYA0KDQpPbiB0cm91dmUgNTIgZ2VucmVzICg1MywgYXVxdWVsIG9uIHJldGlyZSBsZSBnZW5yZSAiTkEiKSBkYW5zIGxlIGZpY2hpZXIgZGVzIGF1dGV1cnMgVExHLCBxdSdpbCBlc3QgZGlmZmljaWxlIGRlIHJlcHLDqXNlbnRlciBjbGFpcmVtZW50IGVuIGNvdWxldXJzLg0KTm91cyBnYXJkb25zIGh1aXQgZ2VucmVzIHBhcm1pIGxlcyBwbHVzIHJlcHLDqXNlbnTDqXMuIENlY2kgZXN0IHVuZSBkw6ltYXJjaGUgZXhwbG9yYXRvaXJlwqA6IGwnaWTDqWFsIHNlcmFpdCDDqXZpZGVtbWVudCBkZSBwcm9kdWlyZSBwbHVzaWV1cnMgZ3JhcGhpcXVlc8KgOyByYXBwZWxvbnMgZW4gb3V0cmUsIGNvbW1lIGlsIGVzdCBleHBsaXF1w6kgW3BsdXMgaGF1dF0oI3ZhcmlhYmxlcy1yZWNoZXJjaMOpZXMpLCBxdWUgbG9yc3F1ZSBwbHVzaWV1cnMgZ2VucmVzIHMnYXBwbGlxdWVudCDDoCB1biBhdXRldXIsIG5vdXMgYXZvbnMgZ2FyZMOpIGxlIHByZW1pZXIgYXBwYXJhaXNzYW50IHBhciBvcmRyZSBhbHBoYWLDqXRpcXVlLg0KDQpgYGB7ciB0bGctZ2VucmUtc3RhdHMsIHJvd3MucHJpbnQgPSAxMX0NCmNvdW50X3RsZ19nZW5yZSA8LQ0KICB0bGdfYXV0aG9yc19kZiAlPiUNCiAgY291bnQoZ2VucmUsIHNvcnQgPSBUUlVFKQ0Ka25pdF9wcmludChjb3VudF90bGdfZ2VucmVbMToxMSxdKQ0KYGBgDQoNCkRlIGNldHRlIGxpc3RlLCBub3VzIGF2b25zIMOpbGltaW7DqSBsZXMgIipIaXN0b3JpY2kvLWFlKiIgdHJvcCBkaXNwZXJzw6lzIGFwcG9ydGFudCBkZSBsYSBjb25mdXNpb24gZGFucyBsYSBsZWN0dXJlLCBldCBsZXMgIipTY3JpcHRvcmVzIEVjY2xlc2lhc3RpY2kqIiwgYXNzZXogZGlzcGVyc8OpcyDDqWdhbGVtZW50LCBtw6ptZSBzJ2lscyBuJ2FwcGFyYWlzc2VudCBxdWUgdGFyZGl2ZW1lbnQuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtZ2VucmV9DQojIE9uIGFwcGxpcXVlIDggZ2VucmVzIGF2ZWMgdW5lIHPDqWxlY3Rpb24gZGUgY291bGV1cnMNCnRsZ19hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIoZ2VucmUgJWluJSBjKA0KICAgICJQaGlsb3NvcGhpY2kvLWFlIiwgIkNvbWljaSIsICJUcmFnaWNpIiwgIkdyYW1tYXRpY2kiLA0KICAgICJFcGljaS8tYWUiLCAiTHlyaWNpLy1hZSIsICJSaGV0b3JpY2kiLCAiTWVkaWNpIg0KICApKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gZ2VucmUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHhsaW0oMCwgMjgwMCkgKw0KICB5bGltKC0zNTAsIDYwMCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY291bGV1cnNbYygxLCA0LCA2LCA5LCAxMSwgMTUsIDIwLCAyNSldKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRywgZGF0ZXMgZXQgZ2VucmVzIGxpdHTDqXJhaXJlcyIpDQpgYGANCg0KRGUgY2UgcHJlbWllciBncmFwaGlxdWUsIGlsIGFwcGFyYcOudCBxdWUgbGVzIHBoaWxvc29waGVzIHNvbnQgZGlzcGVyc8OpcywgbWFpcyByZXN0ZW50IGVuIGRlaG9ycyBkZSBsYSB6b25lIGRlcyBjb21pcXVlcyBldCBkZXMgdHJhZ2lxdWVzLiBOb3VzIG9ic2Vydm9ucyBhdXNzaSB1biBsb25ndWUgbGlnbmUgdmVydGljYWxlIHJlcHLDqXNlbnRhbnQgbGVzIG3DqWRlY2lucy4gQ2V0dGUgb2JzZXJ2YXRpb24gZXN0IHBsdXMgcGFybGFudGUgc2kgbm91cyBuZSBnYXJkb25zIHBsdXMgcXVlIGNlcyBxdWF0cmUgZGVybmllcnMgZ2VucmVzLg0KDQpgYGB7ciB0bGctY29kZS1kYXRlLTRnZW5yZXN9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKGdlbnJlICVpbiUgYygNCiAgICAiUGhpbG9zb3BoaWNpLy1hZSIsICJDb21pY2kiLCAiVHJhZ2ljaSIsICJNZWRpY2kiDQogICkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBnZW5yZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgwLCAyODAwKSArDQogIHlsaW0oLTM1MCwgNjAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDYsIDE1LCAyNSldKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRywgZGF0ZXMgZXQgcXVhdHJlIGdlbnJlcyIpDQpgYGANCg0KSWwgZXN0IGN1cmlldXggZGUgY29uc3RhdGVyIHF1ZSBsYSBjb23DqWRpZSBzZW1ibGUgZW5jYWRyw6llIHBhciBsYSB0cmFnw6lkaWUuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtM2dlbnJlc30NCiMgWm9vbSBzdXIgbGVzIGlkZW50aWZpYW50cyBkZXMgY29taXF1ZXMsIG3DqWRlY2lucyBldCB0cmFnaXF1ZXMuDQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKGdlbnJlICVpbiUgYygiQ29taWNpIiwgIlRyYWdpY2kiLCAiTWVkaWNpIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBnZW5yZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgwLCAyMDAwKSArDQogIHlsaW0oLTM1MCwgNjAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDYsIDI1KV0pICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBkYXRlcyBldCB0cm9pcyBnZW5yZXMiKQ0KYGBgDQoNCkVuIGZhaXQsIG9uIG9ic2VydmUgcXVlIGxlcyBjb21pcXVlcyByZWdyb3Vww6lzIGRlIGxhIHNvcnRlIGNvcnJlc3BvbmRlbnQgw6AgbGEgc8OpcXVlbmNlIHF1ZSBub3VzIGF2aW9ucyByZWxldsOpLCBlbnRyZSB+MzkwIGV0IH41MjAsIGRhbnMgbm90cmUgcHJlbWnDqHJlIGFuYWx5c2UgKHZvaXIgbGEgc2VjdGlvbiBbIkxlcyBpZGVudGlmaWFudHMgcGFyIGxlcyBub21zIl0oI2xlcy1pZGVudGlmaWFudHMtcGFyLWxlcy1ub21zKSkuDQoNCmBgYHtyfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihnZW5yZSAlaW4lIGMoIkNvbWljaSIsICJUcmFnaWNpIiwgIk1lZGljaSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpLCBjb2xvciA9IGdlbnJlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDAsIDEwMDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzW2MoMSwgNiwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIG5vbXMgZXQgdHJvaXMgZ2VucmVzIiwgeSA9ICJuYW1lIikNCmBgYA0KDQpPbiB2b2l0IGNsYWlyZW1lbnQgYXBwYXJhw650cmUgbGVzIGNvbWlxdWVzIHJhbmfDqXMgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWXCoCEgU2kgdW5lIGxpZ25lIHZlcnRpY2FsZSBhcHBhcmHDrnQgYXZlYyBsZXMgdHJhZ2lxdWVzLCBlbnRyZSB+MjYwIGV0IH4zODAsIHZvaXJlIGVudHJlIH42MjAgZXQgfjc1MCBwb3VyIGxlcyBtw6lkZWNpbnMsIGNlcyBkZXV4IGNhdMOpZ29yaWVzIHBhcmFpc3NlbnQgbsOpYW5tb2lucyBuZSBwYXMgw6p0cmUgcmFuZ8OpZXMgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUuDQoNClRlbnRvbnMgdW5lIGRlcm5pw6hyZSBzw6lyaWUgZGUgZ3JhcGhpcXVlcywgcmVwcsOpc2VudGFudCBsZXMgaWRlbnRpZmlhbnRzIGVuIGZvbmN0aW9uIGRlcyBub21zLCBhdmVjIGxlcyBnZW5yZXMgZW4gY291bGV1cnMuDQoNCmBgYHtyfQ0KdG1wX3RsZ19hdXRob3JzX2dlbnJlcyA8LQ0KICB0bGdfYXV0aG9yc19kZiAlPiUNCiAgZHJvcF9uYShnZW5yZSkgJT4lDQogIGNvdW50KGdlbnJlKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgcHVsbChnZW5yZSkNCg0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihnZW5yZSAlaW4lIHRtcF90bGdfYXV0aG9yc19nZW5yZXNbMDo4XSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSBmY3RfcmVvcmRlcihuYW1lLCBkZXNjKG5hbWUpKSwgY29sb3IgPSBnZW5yZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgwLCA1MDAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDQsIDYsIDksIDExLCAxNSwgMjAsIDI1KV0pICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBub21zIGV0IGdlbnJlcyBsaXR0w6lyYWlyZXMgKHPDqXJpZSAxKSIsIHkgPSAibmFtZSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpDQoNCnRsZ19hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIoZ2VucmUgJWluJSB0bXBfdGxnX2F1dGhvcnNfZ2VucmVzWzk6MTZdKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpLCBjb2xvciA9IGdlbnJlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDAsIDUwMDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzW2MoMSwgNCwgNiwgOSwgMTEsIDE1LCAyMCwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIG5vbXMgZXQgZ2VucmVzIGxpdHTDqXJhaXJlcyAoc8OpcmllIDIpIiwgeSA9ICJuYW1lIikgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihnZW5yZSAlaW4lIHRtcF90bGdfYXV0aG9yc19nZW5yZXNbMTc6MjRdKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGZjdF9yZW9yZGVyKG5hbWUsIGRlc2MobmFtZSkpLCBjb2xvciA9IGdlbnJlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDAsIDUwMDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzW2MoMSwgNCwgNiwgOSwgMTEsIDE1LCAyMCwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIG5vbXMgZXQgZ2VucmVzIGxpdHTDqXJhaXJlcyAoc8OpcmllIDMpIiwgeSA9ICJuYW1lIikgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KcmVtb3ZlKHRtcF90bGdfYXV0aG9yc19nZW5yZXMpDQpgYGANCg0KUmllbiBkJ2V4dHLDqm1lbWVudCBjbGFpciBuZSBzZSBkaXN0aW5ndWUsIGVuIHN1cyBkZSBjZSBxdWUgbm91cyBhdm9ucyByZW1hcnF1w6kgYXVwYXJhdmFudCwgc2kgY2Ugbidlc3Qgw6l2ZW50dWVsbGVtZW50IHVuIGdyb3VwZW1lbnQgZGUgcG/DqHRlcyBseXJpcXVlcyBhdXRvdXIgZGUgMjUwIChzw6lyaWUgMiksIGV0IGRlICIqUG9ldGFlKiIgYXV0b3VyIGRlIDI2MDAgKHPDqXJpZSAzKSwgbWFpcyBxdWkgbmUgcGFyYWlzc2VudCBwYXMgY2xhc3PDqXMgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUuDQoNCklsIGZhdWRyYWl0IHJlZ2FyZGVyIGxlcyBjaG9zZXMgcGx1cyBlbiBkw6l0YWlsLCBldCDDqXZlbnR1ZWxsZW1lbnQgbW9kaWZpZXIgb3UgY29tcGzDqXRlciBub3MgZG9ubsOpZXMgZGUgZMOpcGFydMKgOiByYXBwZWxvbnMgcXVlIHBvdXIgdW4gZ3JhbmQgbm9tYnJlIGQnYXV0ZXVycywgbGVzIGdlbnJlcywgcsOpY3Vww6lyw6lzIGR1IENMVEssIG5vdXMgc29udCBtYW5xdWFudHMuIERlIG3Dqm1lLCBsZXMgZGF0ZXMgcmV0ZW51ZXMgcG91cnJhaWVudCDDqnRyZSBpbXByw6ljaXNlcywgb3UgbGVzIG5vbXMgcG91cnJhaWVudCDDqnRyZSBkaWZmw6lyZW50cyBkZSBjZXV4IHJldGVudXMgYXUgbW9tZW50IGRlIGxhIGNsYXNzaWZpY2F0aW9uwqDigJMgdm9pcmUsIHBvdXIgw6p0cmUgcGx1cyBwcsOpY2lzLCBsZXMgbm9tcyBwb3VycmFpZW50LCBzYW5zIMOqdHJlIHRvdGFsZW1lbnQgZGlmZsOpcmVudHMsIMOqdHJlIGluZGV4w6lzIMOgIHVuZSBpbml0aWFsZSBkaXN0aW5jdGUgZGUgbGEgcHJlbWnDqHJlIGxldHRyZSBhcHBhcmFpc3NhbnQgZGFucyBsZSBub20gZG9udCBub3VzIGRpc3Bvc29ucy4NCg0KIyMjIDIuNS4gSWRlbnRpZmlhbnRzIGV0IGxpZXV4DQoNClBvdXIgbGEgY2xhc3NpZmljYXRpb24gUEhJLCBsJ2Vzc2VudGllbCBwYXJhw650IGV4cGxpcXXDqcKg4oCTIGlsIG5lIHJlc3RlcmFpdCBxdSfDoCBkw6l0ZXJtaW5lciBwbHVzIHByw6ljaXPDqW1lbnQgbGVzIGZyb250acOocmVzIGRlcyBww6lyaW9kZXMgY29uc2lkw6lyw6llcywgYWluc2kgcXVlIGxlcyBub21zIHV0aWxpc8OpcywgZXQgw6l2ZW50dWVsbGVtZW50LCBsYSByYWlzb24gZGVzICJ0cm91cyIgZGFucyBsYSBudW3DqXJvdGF0aW9uLg0KDQpJbCBuZSBub3VzIHJlc3RlIHBsdXMgcXUnw6AgZXNzYXllciBkJ2V4cGxpcXVlciwgcG91ciBsYSBjbGFzc2lmaWNhdGlvbiBUTEcsIGQndW5lIHBhcnQgbCdvcmRyZSBkZXMgc8OpcXVlbmNlcywgZCdhdXRyZSBwYXJ0IGNlcnRhaW5lcyBzw6lxdWVuY2VzIHBhcnRpY3VsacOocmVzLCBkb250IHBvdXIgY2VydGFpbmVzIGF1Y3VuZSBsb2dpcXVlIGNsYWlyZSBuJ2VzdCBhcHBhcnVlIGp1c3F1ZS1sw6AuIFBvdXIgbCdvcmRyZSBkZXMgc8OpcXVlbmNlcyBlbnRyZSBlbGxlcywgbGEgbG9naXF1ZSBwYXJhw650IGRpZmZpY2lsZSDDoCDDqWx1Y2lkZXIgcGFyIGxhIGNvbmZyb250YXRpb24gZGVzIHZhcmlhYmxlcyDDoCBub3RyZSBkaXNwb3NpdGlvbi4gUG91ciBjZSBxdWkgZXN0IGRlcyBwb3J0aW9ucyBpbmV4cGxpcXXDqWVzLCBpbnTDqXJlc3NvbnMtbm91cyBlbiBwYXJ0aWN1bGllciBhdXggaWRlbnRpZmlhbnRzIGF1LWRlbMOgIGRlIDE4MDAsIHF1aSBuZSBzdWl2YWllbnQgdnJhaXNlbWJsYWJsZW1lbnQgcGFzIGxhIGxvZ2lxdWUgYWxwaGFiw6l0aXF1ZS4NCg0KVGVudG9ucyBkb25jIGQnb2JzZXJ2ZXIgc2kgbGVzIGxpZXV4IHBvdXJyYWllbnQgam91ZXIgdW4gcsO0bGUgZGFucyBsJ2F0dHJpYnV0aW9uIGRlcyBpZGVudGlmaWFudHMgbnVtw6lyb3TDqXMgw6AgcGFydGlyIGRlIDE4MDAuDQoNCmBgYHtyfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihjb2RlID4gMTgwMCAmIGNvZGUgPCA1MDAwKSAlPiUNCiAgZHJvcF9uYShwbGFjZSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSBmY3RfcmVvcmRlcihwbGFjZSwgZGVzYyhwbGFjZSkpLCBjb2xvciA9IHBsYWNlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhjb3VsZXVycywgIiMwMDAwMDAiLCAiIzAwMDAwMCIpKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRyBldCBsaWV1eCAoMTgwMC01MDAwKSIsIHkgPSAicGxhY2UiKQ0KYGBgDQoNClJpZW4gZCfDqXZpZGVudCBuZSBzZSBkw6lnYWdlIGRlIGNlIHByZW1pZXIgZ3JhcGhpcXVlwqA6IHVuIG3Dqm1lIGxpZXUgc2UgcsOpcGFydGl0IHNvdXZlbnQgdG91dCBhdSBsb25nIGRlIGxhIG51bcOpcm90YXRpb24uIEVzc2F5b25zIGRlIGNyb2lzZXIgYXZlYyBsZXMgZGF0ZXMgcG91ciBkaXN0aW5ndWVyIGRlcyB0ZW5kYW5jZXMuDQoNCkNvbW1lIGxhIGNvbG9ubmUgImBwbGFjZWAiIGNvbnRpZW50IDQ3IGxpZXV4IGRpZmbDqXJlbnRzLCBjZWxhIG5lIHNlcmEgcGFzIGxpc2libGUgc2kgbm91cyBhdHRyaWJ1b25zIHVuZSBjb3VsZXVyIMOgIGNoYWN1biBkJ2V1eC4gTm91cyBhbGxvbnMgZMOpdGVybWluZXIgbGVzIGxpZXV4IHF1aSBhcHBhcmFpc3NlbnQgbGUgcGx1cyBmcsOpcXVlbW1lbnQsIHBvdXIgbGVzIGNvZGVzIDE4MDAgZXQgcGx1cy4NCg0KYGBge3IgdGxnLXBsYWNlLWNvZGVzLXBsdXMtMTgwMC1zdGF0cywgcm93cy5wcmludCA9IDExfQ0KY291bnRfdGxnX3BsYWNlIDwtDQogIHRsZ19hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIoY29kZSA+IDE4MDApICU+JQ0KICBjb3VudChwbGFjZSwgc29ydCA9IFRSVUUpDQprbml0X3ByaW50KGNvdW50X3RsZ19wbGFjZVsxOjExLF0pDQpgYGANCg0KQ29tbWUgbm91cyBsJ2F2b25zIGZhaXQgcG91ciBsZXMgZ2VucmVzLCBub3VzIGdhcmRvbnMgbGVzIDggcGF5cyBwb3VyIGxlc3F1ZWxzIG5vdXMgb2JzZXJ2b25zIGxlIHBsdXMgZCdvY2N1cnJlbmNlcyAoaWNpLCBhdSBtb2lucyA3IG9jY3VycmVuY2VzLCBlbiBjaG9pc2lzc2FudCBhcmJpdHJhaXJlbWVudCBDaHlwcmUgcGx1dMO0dCBxdWUgbGEgTGlieWUgcXVpIHNvbnQgKmV4IGFlcXVvKikuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtbGlldS1wbHVzLTE4MDAtOC1wYXlzfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihwbGFjZSAlaW4lIGMoDQogICAgIlR1cmtleSIsICJHcmVlY2UiLCAiRWd5cHQiLCAiSXRhbHkiLA0KICAgICJTeXJpYSIsICJJc3JhZWwiLCAiUGFsZXN0aW5lIiwgIkN5cHJ1cyINCiAgKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSBkYXRlLCBjb2xvciA9IHBsYWNlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDE4MDAsIDUwMDApICsNCiAgeWxpbSgtMzUwLCAxNjAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDQsIDYsIDksIDExLCAxNSwgMjAsIDI1KV0pICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBkYXRlcyBldCBsaWV1eCAoMTgwMC01MDAwKSIpDQpgYGANCg0KT24gb2JzZXJ2ZSBwbHVzaWV1cnMgbGlnbmVzIHZlcnRpY2FsZXMgcmVwcsOpc2VudGFudCBkZXMgYXV0ZXVycyBkZSBUdXJxdWllIDogbCd1bmUgdmVycyBsZSBjb2RlIDI3NTAsIGNvbmNlcm5lIGRlcyBhdXRldXJzIGQnZW52aXJvbiAxMjAwIMOgIGVudmlyb24gMTQwMDsgbCdhdXRyZSBkYW5zIGxlcyBjb2RlcyAzMDAwIGNvbmNlcm5lIGRlcyBhdXRldXJzIGRlIDgwMCDDoCAxNTAwwqA7IGlsIHNlbWJsZSDDqWdhbGVtZW50IHkgYXZvaXIgZGVzIGxpZ25lcyBjb25jZXJuYW50IGRlcyBhdXRldXJzIGQnw4lneXB0ZS4gQ29tbWUgaWwgZXN0IGRpZmZpY2lsZSBkZSBsaXJlIGNlIGdyYXBoaXF1ZSwgbm91cyDDqWxpbWlub25zIGxlcyBsaWV1eCBwb3VyIGxlc3F1ZWxzIG5vdXMgY29uc3RhdG9ucyBtb2lucyBkZSAzMCBvY2N1cnJlbmNlcywgZXQgbm91cyBhbGxvbnMgZGl2aXNlciBsZXMgZ3JhcGhpcXVlcyBlbiAqdHJhbmNoZXMqIGRlIGNvZGVzLCDDoCBwYXJ0aXIgZGVzIG9ic2VydmF0aW9ucyBkdSB0YWJsZWF1IGVuIGRldXggZGltZW5zaW9ucyAiSWRlbnRpZmlhbnRzIFRMRyBldCBub21zICgwLTUwMDApIiwgZmlndXJhbnQgZGFucyBsYSBzZWN0aW9uIFsiTGVzIGlkZW50aWZpYW50cyBwYXIgbGVzIG5vbXMiXSgjbGVzLWlkZW50aWZpYW50cy1wYXItbGVzLW5vbXMpLiBPbiB5IHZveWFpdCBkZXMgY29uY2VudHJhdGlvbnMgZGUgcG9pbnRzIHF1aSBuZSBmb3JtYWllbnQgcGFzIGRlIGxpZ25lcywgcG91ciBsZXMgY29kZXMgMTgwMCDDoCAzMDAwIGV0IDQwMDAgw6AgNDQwMC4NCg0KYGBge3IgdGxnLWNvZGUtZGF0ZS1saWV1LXBsdXMtMTgwMC01LXBheXN9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKHBsYWNlICVpbiUgYygNCiAgICAiVHVya2V5IiwgIkdyZWVjZSIsICJFZ3lwdCIsICJJdGFseSIsICJTeXJpYSINCiAgKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvZGUsIHkgPSBkYXRlLCBjb2xvciA9IHBsYWNlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB4bGltKDE4MDAsIDMwMDApICsNCiAgeWxpbSgtMzUwLCAxNjAwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDcsIDEzLCAxOSwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIGRhdGVzIGV0IDUgbGlldXggKDE4MDAtMzAwMCkiKQ0KYGBgDQoNCklsIHNlbWJsZXJhaXQgcXVlIHBsdXNpZXVycyBsaWduZXMgc2UgZGVzc2luZW50IGRlIG1hbmnDqHJlIMOpcGFyc2UuIERlIG5vdXZlYXV4IHpvb21zIHNvbnQgbsOpY2Vzc2FpcmVzLg0KDQpgYGB7ciB0bGctY29kZS1kYXRlLTUtbGlldXgtMTgwMC0zMDAwfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihwbGFjZSAlaW4lIGMoDQogICAgIlR1cmtleSIsICJHcmVlY2UiLCAiRWd5cHQiLCAiSXRhbHkiLCAiU3lyaWEiDQogICkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBwbGFjZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgxODAwLCAyMTAwKSArDQogIHlsaW0oLTM1MCwgNzUwKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb3VsZXVyc1tjKDEsIDcsIDEzLCAxOSwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIGRhdGVzIGV0IDUgbGlldXggKDE4MDAtMjEwMCkiKQ0KYGBgDQoNClF1ZWxxdWVzIGTDqWJ1dHMgZGUgbGlnbmVzIGFwcGFyYWlzc2VudCB2ZXJzIDE5NTAsIG1haXMgaWwgZXN0IGRpZmZpY2lsZSBkJ8OpdGFibGlyIHVuZSBjb3Jyw6lsYXRpb24gZW50cmUgY29kZXMgZXQgbGlldXguIExhIGxpZ25lIHJvdWdlIGhvcml6b250YWxlIGFwcGFyYWlzc2FudCBlc3QgcHJvYmFibGVtZW50IGRhdmFudGFnZSBsacOpZSDDoCBsYSBkYXRlIHF1J2F1IGxpZXXCoDogbGlldXggZXQgcMOpcmlvZGVzIGRlIHByb2R1Y3Rpb24gZCfDqWNyaXRzIGdyZWNzIHNvbnQgc291dmVudCBsacOpcy4NCg0KYGBge3IgdGxnLWNvZGUtZGF0ZS01LWxpZXV4LTIxMDAtMjMwMH0NCnRsZ19hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIocGxhY2UgJWluJSBjKA0KICAgICJUdXJrZXkiLCAiR3JlZWNlIiwgIkVneXB0IiwgIkl0YWx5IiwgIlN5cmlhIg0KICApKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gcGxhY2UpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHhsaW0oMjEwMCwgMjMwMCkgKw0KICB5bGltKC0zNTAsIDc1MCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY291bGV1cnNbYygxLCA3LCAxMywgMTksIDI1KV0pICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBkYXRlcyBldCA1IGxpZXV4ICgyMTAwLTIzMDApIikNCmBgYA0KDQpOb3VzIGNvbnN0YXRvbnMgZGVzIGFncsOpZ2F0cyBkZSBwb2ludHMgZGUgbcOqbWUgY291bGV1ciwgbWFpcyBpbCBlc3QgZGlmZmljaWxlIGQnZW4gdGlyZXIgZGVzIGNvbmNsdXNpb25zLCBkJ2F1dGFudCBwbHVzIHF1J2lsIG1hbnF1ZSBiZWF1Y291cCBkZSBsaWV1eCBkb250IGxlcyBwb2ludHMgZGUgY291bGV1cnMgYXVyYWllbnQgYXBwb3J0w6kgZGF2YW50YWdlIGRlIGJydWl0Lg0KDQpgYGB7ciB0bGctY29kZS1kYXRlLTUtbGlldXgtMjcwMC0zMzAwfQ0KdGxnX2F1dGhvcnNfZGYgJT4lDQogIGZpbHRlcihwbGFjZSAlaW4lIGMoDQogICAgIlR1cmtleSIsICJHcmVlY2UiLCAiRWd5cHQiLCAiSXRhbHkiLCAiU3lyaWEiDQogICkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2RlLCB5ID0gZGF0ZSwgY29sb3IgPSBwbGFjZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxpbSgyNzAwLCAzMzAwKSArDQogIHlsaW0oLTM1MCwgMTYwMCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY291bGV1cnNbYygxLCA3LCAxMywgMTksIDI1KV0pICsNCiAgbGFicyh0aXRsZSA9ICJJZGVudGlmaWFudHMgVExHLCBkYXRlcyBldCA1IGxpZXV4ICgyNzAwLTMzMDApIikNCmBgYA0KDQpDZXR0ZSBwb3J0aW9uIGEgcG91ciBjYXJhY3TDqXJpc3RpcXVlIGRlIGNvbmNlcm5lciBwcmVzcXVlIGV4Y2x1c2l2ZW1lbnQgbGEgVHVycXVpZSwgZHUgbW9pbnMgcG91ciBsZXMgem9uZXMgcmV0ZW51ZXMuDQoNCmBgYHtyIHRsZy1jb2RlLWRhdGUtOC1saWV1eC0yNzAwLTMzMDB9DQp0bGdfYXV0aG9yc19kZiAlPiUNCiAgZmlsdGVyKHBsYWNlICVpbiUgYygNCiAgICAiVHVya2V5IiwgIkdyZWVjZSIsICJFZ3lwdCIsICJJdGFseSIsDQogICAgIlN5cmlhIiwgIklzcmFlbCIsICJQYWxlc3RpbmUiLCAiQ3lwcnVzIg0KICApKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gcGxhY2UpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHhsaW0oMjcwMCwgMzMwMCkgKw0KICB5bGltKC0zNTAsIDE2MDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzW2MoMSwgNCwgNiwgOSwgMTEsIDE1LCAyMCwgMjUpXSkgKw0KICBsYWJzKHRpdGxlID0gIklkZW50aWZpYW50cyBUTEcsIGRhdGVzIGV0IDggbGlldXggKDI3MDAtMzMwMCkiKQ0KYGBgDQoNCkNlbGEgc2VtYmxlIHNlIGNvbmZpcm1lciBsb3JzcXVlIG5vdXMgw6lsYXJnaXNzb25zIGNldHRlIG9ic2VydmF0aW9uIGF1eCBodWl0IHBheXMgbGVzIHBsdXMgaW1wb3J0YW50cyBkZSBsYSB0cmFuY2hlIDE4MDAgZXQgcGx1cy4gQ2VwZW5kYW50LCB1bmUgcmVjaGVyY2hlIMOpbGFyZ2llIMOgIHRvdXMgbGVzIGxpZXV4IHBlcm1ldHRyYWl0IHBldXQtw6p0cmUgZCdhcHBvcnRlciB1bmUgY29uY2x1c2lvbi4gTWFsaGV1cmV1c2VtZW50LCBlbGxlIGVzdCBpbXBvc3NpYmxlIGF2ZWMgbGEgcGzDqXRob3JlIGRlcyA1MiBjb3VsZXVycywgc3VydG91dCBxdWUgZ2dwcGxvdCBsZXMgZMOpdGVybWluZSBzZWxvbiBsJ29yZHJlIGFscGhhYsOpdGlxdWUgZXQgbm9uIHNlbG9uIGxhIHByb3hpbWl0w6kgZ8Opb2dyYXBoaXF1ZS4NCg0KYGBge3IgdGxnLWNvZGUtZGF0ZS01LWxpZXV4LTQwMDAtNDQwMH0NCnRsZ19hdXRob3JzX2RmICU+JQ0KICBmaWx0ZXIocGxhY2UgJWluJSBjKA0KICAgICJUdXJrZXkiLCAiR3JlZWNlIiwgIkVneXB0IiwgIkl0YWx5IiwgIlN5cmlhIg0KICApKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29kZSwgeSA9IGRhdGUsIGNvbG9yID0gcGxhY2UpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHhsaW0oNDAwMCwgNDQwMCkgKw0KICB5bGltKC0zNTAsIDE2MDApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvdWxldXJzW2MoMSwgNywgMTMsIDE5LCAyNSldKSArDQogIGxhYnModGl0bGUgPSAiSWRlbnRpZmlhbnRzIFRMRywgZGF0ZXMgZXQgNSBsaWV1eCAoNDAwMC00NDAwKSIpDQpgYGANCg0KUmllbiBkZSBzaWduaWZpY2F0aWYgbmUgc2VtYmxlIMOpbWVyZ2VyIGRlIGNldHRlIHRyYW5jaGUuDQoNClJpZW4gZGUgdHLDqHMgY29uY2x1c2lmIG4nYXBwYXJhw650IGRlIGNldHRlIHJlY2hlcmNoZSBzdXIgbGVzIGxpZXV4IGRlcyBhdXRldXJzIGVuIHJhcHBvcnQgYXZlYyBsZSBjb2RlIFRMRyBhdSBkZWzDoCBkZSAxODAwLg0KDQojIyBDb25jbHVzaW9uDQoNCkFwcsOocyBjZXR0ZSBleHBsb3JhdGlvbiwgbm91cyBwb3V2b25zIGNvbmNsdXJlIHBsdXNpZXVycyBjaG9zZXPCoOKAkyBjb25jbHVzaW9ucyBxdWkgcG91cnJhaWVudCDDqnRyZSBwcsOpY2lzw6llcyBldCBlbnJpY2hpZXMgw6AgZGUgbm9tYnJldXggw6lnYXJkcy4NCg0KIyMjIFN5bnRow6hzZSBkZXMgcsOpc3VsdGF0cw0KDQpDb21tZSBub3VzIGwnYXZpb25zIHByZXNzZW50aSBkZXZhbnQgbGUgY2FyYWN0w6hyZSBub24tw6l2aWRlbnQgZGUgbGEgbnVtw6lyb3RhdGlvbiwgbm91cyBhdm9ucyDDqXRhYmxpIHF1ZSBsJ2F0dHJpYnV0aW9uIGRlcyBpZGVudGlmaWFudHMgbmUgcmVjb3V2cmUgcGFyIHVuZSBsb2dpcXVlIHVuaWZvcm1lLCBtYWlzIG9iw6lpdCDDoCB1bmUgcGx1cmFsaXTDqXMgZGUgZmFjdGV1cnMuIMOAIGNldCDDqWdhcmQsIGwnZW1wbG9pIGQnYW5hbHlzZXMgZ3JhcGhpcXVlcyBzJ2VzdCByw6l2w6lsw6kgcGFydGljdWxpw6hyZW1lbnQgZsOpY29uZC4gTm91cyBhdm9ucyBkZSBwbHVzIHB1IMOpdGFibGlyIGwnZXhpc3RlbmNlIGRlIHPDqXF1ZW5jZXMgc3DDqWNpZmlxdWVzLCBwb3Nzw6lkYW50IHBhcmZvaXMgY2hhY3VuZSB1bmUgbG9naXF1ZSBwcm9wcmUuDQoNCioqRGFucyBsZSBjYXMgZHUgY29kZSBQSEkqKiBkZXMgdGV4dGVzIGxhdGlucyBkdSBwcm9qZXQgKlBlcnNldXMqLCB1biBwcmVtaWVyIGTDqWNvdXBhZ2UgZXN0ICoqY2hyb25vbG9naXF1ZSoqLCBsZSBjb2RlIMOpdGFudCBwcm9wb3J0aW9ubmVsIGF1eCBkYXRlcyBkZSBjaGFxdWUgYXV0ZXVyLCBldCBsZSBzZWNvbmQsIGF1IHNlaW4gZGUgY2hhcXVlIHDDqXJpb2RlIGFpbnNpIGTDqWZpbmllLCBlc3QgKiphbHBoYWLDqXRpcXVlKiouIExlIGTDqXRhaWwgZGVzIGRhdGVzIHJldGVudWVzIHBvdXIgbGEgY2xhc3NpZmljYXRpb24sIGFpbnNpIHF1ZSBkdSB0ZXJtZSBzdXIgbGVxdWVsIHNlIGZvbmRlIGxhIGNsYXNzaWZpY2F0aW9uIGFscGhhYsOpdGlxdWUsIHBvdXJyYWl0IMOqdHJlIGFmZmluw6nCoOKAkyBkdSBtb2lucyBhdm9ucy1ub3VzIMOpdGFibGkgcXVlIGwnaW5kZXhhdGlvbiBhbHBoYWLDqXRpcXVlIG5lIHMnYXBwdXlhaXQgcGFzIHN1ciBsZSAqcHJhZW5vbWVuKi4gQ2VzIGRldXggbG9naXF1ZXMgc2VtYmxlbnQgcmVjb3V2cmlyIGRlIG1hbmnDqHJlIGhvbW9nw6huZSBsJ2Vuc2VtYmxlIGRlIGxhIG51bcOpcm90YXRpb24sIGxlcyBwb2ludHMgYWJlcnJhbnRzIGFwcGVsYW50IMOgIMOqdHJlIMOpdHVkacOpcyBhdSBjYXMgcGFyIGNhcywgcGFyIGV4ZW1wbGUgcG91ciB2w6lyaWZpZXIgbGUgbm9tIGVtcGxvecOpLg0KDQoqKkxlcyBpZGVudGlmaWFudHMgZHUgKlRoZXNhdXJ1cyBMaW5ndWFlIEdyYWVjYWUqKiosIHBsdXMgbm9tYnJldXgsIHN1aXZlbnQgZGVzIHLDqGdsZXMgZGF2YW50YWdlIGNvbXBsZXhlcy4gT24geSBhcGVyw6dvaXQgcGx1c2lldXJzIHPDqXF1ZW5jZXMsIHBvdXIgY2VydGFpbmVzIGRlc3F1ZWxsZXMgbm91cyBzb21tZXMgcGFydmVudXMgw6AgcmVzdGl0dWVyIGxhIGxvZ2lxdWUuIE5vdXMgYXZvbnMgYWluc2kgZGlzY2VybsOpIHF1YXRyZSBzw6lxdWVuY2VzIG9yZG9ubsOpZXMgcGFyIG9yZHJlIGFscGhhYsOpdGlxdWUsIGRvbnQgbCd1bmUgY29ycmVzcG9uZCBhdXggYXV0ZXVycyBjb21pcXVlcy4gRCdhdXRyZXMgcmVncm91cGVtZW50cyBzZSBmb250IMOpZ2FsZW1lbnQgcGFyIGdlbnJlIGxpdHTDqXJhaXJlLCBwYXIgZXhlbXBsZSBwb3VyIGxlcyBhdXRldXJzIHRyYWdpcXVlcyBvdSBsZXMgbcOpZGVjaW5zLCBhdmVjIHVuIGNsYXNzZW1lbnQgaW50ZXJuZSBuZSBzdWl2YW50IHBhcyBsJ29yZHJlIGFscGhhYsOpdGlxdWUuIEQnYXV0cmVzIHBhcnRpZSBkZSBsYSBudW3DqXJvdGF0aW9uIG5vdXMgc29udCBlbiByZXZhbmNoZSByZXN0w6llcyBvYnNjdXJlcy4gTm9zIGFuYWx5c2VzIGV4cGxvcmF0b2lyZXMgbidvbnQgbm90YW1tZW50IHBhcyBwZXJtaXMgZGUgZGlzY2VybmVyIGRlIGNsYXNzaWZpY2F0aW9uIHBhciBsaWV1Lg0KDQojIyMgUGlzdGVzIHBvdXIgZXhwbG9yYXRpb24gdWx0w6lyaWV1cmUNCg0KTm91cyBzb21tZXMgYWluc2kgcGFydmVudXMgw6AgZMOpZnJpY2hlciBsZSB0ZXJyYWluIGV0IMOgIMOpdGFibGlyIGNlcnRhaW5lcyBsaWduZXMgZGUgZm9yY2UgZ3VpZGFudCBsYSBudW3DqXJvdGF0aW9uIGRlcyBpZGVudGlmaWFudHMgY2xhc3NpcXVlcyBjb25zaWTDqXLDqXMuIExlcyBleHBsaWNhdGlvbnMgYXUgZGVtZXVyYW50IHBldXZlbnQgZW5jb3JlIMOqdHJlIHByw6ljaXPDqWVzLiBMZSBwcsOpc2VudCB0cmF2YWlsIHBvdXJyYWl0IGFpbnNpIGFpc8OpbWVudCDDqnRyZSBjb21wbMOpdMOpLCBlbiBwYXJ0YW50IGRlcyBkb25uw6llcyBtaXNlcyBhdSBwcm9wcmVzIHF1ZSBub3VzIGF2b25zIMOpdGFibGllcywgeSBhZGpvaWduYW50IGRlcyB2YXJpYWJsZXMgb3UgZW4gcmFmZmluYW50IGNlbGxlcyBleGlzdGFudGVzLCBldCBlbiBlbXBsb3lhbnQgZGVzIG3DqXRob2RlcyBkJ2FuYWx5c2Ugc2ltaWxhaXJlcywgw6l2ZW50dWVsbGVtZW50IMOpY2xhaXLDqSBwYXIgZGVzIHNhaWxsaWVzIHBsdXMgaW5kaXZpZHVlbGxlcyBzdXIgbGVzIHRhYmxlYXV4IGV0IGxldXJzIMOpbMOpbWVudHMuIERlIG5vbWJyZXVzZXMgcGlzdGVzIHNlIHNvbnQgZW4gZWZmZXQgcHLDqXNlbnTDqWVzIMOgIG5vdXMsIHNhbnMgcXUnaWwgbm91cyBhaXQgw6l0w6kgcG9zc2libGUgZGUgdG91dCDDoCBmYWl0IGxlcyBleHBsb3JlciBkYW5zIGxlIHRlbXBzIHF1aSBub3VzIMOpdGFpdCBpbXBhcnRpLg0KDQojIyMjIFJhZmZpbmVtZW50IGRlcyB2YXJpYWJsZXMgZXhpc3RhbnRlcw0KDQpDb21tZSBub3VzIGwnYXZvbnMgZmFpdCByZW1hcnF1ZXIgYXUgY291cnMgZGUgbm90cmUgw6l0dWRlLCBwbHVzaWV1cnMgZGVzIHZhcmlhYmxlcyBxdWUgbm91cyBhdm9ucyBlbXBsb3nDqSBwcsOpc2VudGVudCBkZXMgYXNww6lyaXTDqXMgcXUnaWwgc2VyYWl0IHBvc3NpYmxlIGQnYXJyb25kaXIuDQoNClBvdXIgY2UgcXVpIGVzdCBkZXMgKipub21zKiosIG5vdXMgYXZvbnMgdnUgcXVlIGxlIHRlcm1lIGVtcGxvecOpIHBvdXIgbCdpbmRleGF0aW9uIGFscGhhYsOpdGlxdWUgw6l0YWl0IGQnaW1wb3J0YW5jZcKgOiByw6ljdXDDqXJlciBwbHVzIHByb3ByZW1lbnQgbGVzIG5vbXMgZGUgcsOpZsOpcmVuY2VzIGRlcyBhdXRldXJzIGxhdGlucyBhdXJhaXQgdnJhaXNlbWJsYWJsZW1lbnQgcGVybWlzIGQnYWZmZXJtaXIgbGVzIHLDqXN1bHRhdHMuIElsIGVuIHZhIGRlIG3Dqm1lIHBvdXIgbGVzIGF1dGV1cnMgZ3JlY3MgOiB1biBwcm9ibMOobWUgc2ltaWxhaXJlIHBvdXJyYWl0IGV4cGxpcXVlciBjZXJ0YWlucyBkZXMgcG9pbnRzIGFiZXJyYW50cyBxdWUgbCdvbiBhIHB1IHJldHJvdXZlciBkYW5zIGxlcyBncmFwaGlxdWVzIGNvbmNlcm7DqXMuDQoNClBvdXIgbGVzICoqZGF0ZXMqKiwgaWwgYXVyYWl0IMOpZ2FsZW1lbnQgw6l0w6kgcG9zc2libGUgZGUgbWVuZXIgZGVzIGFuYWx5c2VzIGNvbXBsw6ltZW50YWlyZXMsIGVuIHBhcnRpY3VsaWVyIHBvdXIgY2xhcmlmaWVyIHByw6ljaXPDqW1lbnQgbGUgZMOpY291cGFnZSBkZSBsYSBjbGFzc2lmaWNhdGlvbiBQSEksIGF2ZWMgbGVzIGRvbm7DqWVzIMOpdGFibGllcyBvdSBkZXMgZG9ubsOpZXMgc3VwcGzDqW1lbnRhaXJlcywgcG91ciBkw6l0ZXJtaW5lciBleGFjdGVtZW50IHNpIGxlIGTDqWNvdXBhZ2Ugc2UgZmFpc2FpdCBlbiBmb25jdGlvbiBkZSBsYSBkYXRlIGRlIG5haXNzYW5jZSwgbGEgZGF0ZSBkZSBtb3J0LCBvdSBkJ3VuZSBhdXRyZSBkYXRlIHF1aSBwb3VycmFpdCBwYXIgZXhlbXBsZSBjb3JyZXNwb25kcmUgw6AgY2VsbGUgZCd1bmUgxZN1dnJlIHBhcnRpY3VsacOocmUuDQoNCkVuIGNlIHF1aSBjb25jZXJuZSBsZXMgKipnZW5yZXMqKiwgbGVzIGRvbm7DqWVzIGF1cmFpZW50IHB1IMOqdHJlIGNvbXBsw6l0w6llc8KgOiBwb3VyIGxlcyBhdXRldXJzIGdyZWNzIG5vdGFtbWVudCwgaWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlIGRlIHLDqWN1cMOpcmVyIGwnaW5mb3JtYXRpb24gZGlyZWN0ZW1lbnQgZGVwdWlzIGxhIHZhcmlhYmxlICJub20iLCBlbiBzdXMgZGVzIGRvbm7DqWVzIGR1IENMVEsuIFJhcHBlbG9ucyDDqWdhbGVtZW50IHF1ZSBub3VzIGF2b25zIHJldGVudSBhcmJpdHJhaXJlbWVudCB1biBzZXVsIGdlbnJlIGxvcnNxdSfDoCB1biBpZGVudGlmaWFudCB5IGNvcnJlc3BvbmRhaXQgcGx1c2lldXJzwqDigJMgaWwgYXVyYWl0IMOpdMOpIHBvc3NpYmxlIGRlIGR1cGxpcXVlciBsZXMgbGlnbmVzIGNvbmNlcm7DqWVzIHBvdXIgZmFpcmUgYXBwYXJhw650cmUgbCdpZGVudGlmaWFudCDDoCBjaGFxdWUgZW5kcm9pdCBkZSBjZXMgZ2VucmUgbXVsdGlwbGVzLCBldCBsZSBjYXMgw6ljaMOpYW50IGRlIGTDqXRlcm1pbmVyIMOgIHF1ZWwgZ2VucmUgbCdhdXRldXIgw6l0YWl0IGluZGV4w6kgcG91ciBkw6l0ZXJtaW5lciBzb24gaWRlbnRpZmlhbnQuDQoNClBvdXIgbGVzICoqbGlldXgqKiwgbm91cyBuZSBub3VzIHNvbW1lcyBwZW5jaMOpcyBxdWUgc3VyIGNldXggcXVpIGNvbXBvcnRhaWVudCBsZSBwbHVzIGQnb2NjdXJyZW5jZXMgcG91ciBsZXMgdHJhbmNoZXMgZCdpZGVudGlmaWFudHMgw6l0dWRpw6llcy4gTm91cyBhdXJpb25zIHB1IGdyb3VwZXIgbGVzIGxpZXV4IHBhciByw6lnaW9ucyBnw6lvZ3JhcGhpcXVlcyBvdSBhdSBjb250cmFpcmUgcHJlbmRyZSBlbiBjb21wdGUgbGVzIHZpbGxlcyBsb3JzcXUnZWxsZXMgw6l0YWllbnQgcHLDqWNpc8OpZXMgZXQgcGxhY2VyIGxlcyBpZGVudGlmaWFudHMgZW4gZMOpZ3JhZMOpcyBkZSBjb3VsZXVycyBzdXIgdW5lIGNhcnRlIGfDqW9ncmFwaGlxdWUuIERlIG3Dqm1lLCBub3VzIHJhcHBlbG9ucyBxdWUgbm91cyBuJ2F2b25zIGFyYml0cmFpcmVtZW50IHJldGVudSBxdSd1biBzZXVsIGxpZXUgbG9yc3F1ZSBwbHVzaWV1cnMgZmlndXJhaWVudCBwb3VyIHVuIGF1dGV1ciB1bmlxdWUuDQoNCiMjIyMgQWRqb25jdGlvbiBkZSB2YXJpYWJsZXMgY29ubmV4ZXMNCg0KTGVzIGNhcmFjdMOpcmlzdGlxdWVzIHN1ciBsZXNxdWVsbGVzIG5vdXMgYXZvbnMgZm9uZMOpIG5vcyBhbmFseXNlcyBzb250IHByb3ByZXMgYXV4IGF1dGV1cnMgY29uc2lkw6lyw6lzwqDigJMgbGEgZGF0ZSBkZSBtb3J0IHBhciBleGVtcGxlIGVzdCBiaWVuIHByb3ByZSDDoCBsJ2F1dGV1ciBlbiB0YW50IHF1ZSBwZXJzb25uZS4gTsOpYW5tb2lucywgY2UgYmlhaXMgcG91cnJhaXQgbmUgcGFzIGNvcnJlc3BvbmRyZSB0b3V0IMOgIGZhaXQgw6AgbGEgY29uc3RydWN0aW9uIGRlcyBjb3JwdXMgw6l0dWRpw6lzwqA6IGlsIHNlbWJsZXJhaXQgcXUndW4gaWRlbnRpZmlhbnQgc29pdCBwYXJmb2lzIGF0dHJpYnXDqSDDoCB1biBzb3VzLWVuc2VtYmxlIGQnxZN1dnJlcyBwYXJ0aWN1bGllciwgY29tbWUgbm91cyBsJ2F2b25zIHJlbGV2w6kgcG91ciBsZXMgY29ycmVzcG9uZGFuY2VzIMOpc3BpdG9sYWlyZXMuIElsIHNlIHBvdXJyYWl0IGFsb3JzIHF1ZSBsZXMgaWRlbnRpZmlhbnRzIGTDqXBlbmRlbnQgZGUgdHJhaXRzIHByb3ByZXMgw6AgY2VzICoqxZN1dnJlcyoqwqDigJMgcGFyIGV4ZW1wbGUsIGxlIG5vbWJyZSBkJ8WTdXZyZXMgYXNzb2Npw6llcyDDoCBjZXQgaWRlbnRpZmlhbnQsIG91IGxldXIgbG9uZ3VldXIuIExhIGNvbnN0aXR1dGlvbiBkJ3VuZSBiYXNlIGRlIGRvbm7DqWVzIGNvbm5leGVzIGNvbXByZW5hbnQgbGVzIMWTdXZyZXMgcsOpcGVydG9yacOpZXMgcG91cnJhaXQgw6AgY2V0IMOpZ2FyZCBzZSBtb250cmVyIHV0aWxlLg0KDQpVbiBhdXRyZSB0cmFpdCBmb25kYW1lbnRhbCBwb3VyIHVuIGNsYXNzaWNpc3RlLCBwb3V2YW50IGFsb3JzIGVudHJlciBlbiBsaWduZSBkZSBjb21wdGUsIHNlcmFpdCBjZWx1aSBkZSBsYSAqKmNhbm9uaWNpdMOpKiouIEVuIGVmZmV0LCBjZXJ0YWlucyBhdXRldXJzIGNvbnNpZMOpcsOpcyBjb21tZSBjYW5vbnMgYXBwYXJhaXNzZW50IGRhbnMgbGEgdHJhZGl0aW9uIGNvbW1lIHBsdXMgaW1wb3J0YW50cyBxdWUgZCdhdXRyZXMuIExlcyDDqXF1aXBlcyBheWFudCBwcmlzIGVuIGNoYXJnZSBsYSBudW3DqXJpc2F0aW9uIGRlcyDFk3V2cmVzIGR1IFRMRyBldCBkdSBjYXRhbG9ndWUgUGVyc2V1cyBvbnQgcHUgYWluc2kgcHJvY8OpZGVyIGVuIHByaW9yaXTDqSDDoCBsJ2ludmVudGFpcmUgZGVzIGF1dGV1cnMganVnw6lzIGxlcyBwbHVzIGltcG9ydGFudHMsIGFwcGFyYWlzc2FudCBhbG9ycyB2cmFpc2VtYmxhYmxlbWVudCBhdSBkw6lidXQgZGUgbGEgY2xhc3NpZmljYXRpb24uIFNpIGNldHRlIGRpbWVuc2lvbiBuJ2VzdCBwYXMgYWlzw6ltZW50IGZvcm1hbGlzYWJsZSBvdSBxdWFudGlmaWFibGUsIGVsbGUgZXN0IMOgIGNvbnNpZMOpcmVyLCBldCB1biDFk2lsIGNvbm5haXNzZXVyIGRlIGxhIHRyYWRpdGlvbiBwb3VycmFpdCBsYSBkaXNjZXJuZXIgc3VyIGxlcyBwcmVtacOocmVzIGNlbnRhaW5lcyBkJ2lkZW50aWZpYW50cyBkdSBUTEcgbm90YW1tZW50wqDigJMgbGVzIGNvcnB1cyBjYW5vbnMgw6l0YW50IHNvdXZlbnQgY2V1eCBsZXMgbWlldXggY29uc2VydsOpcywgZnLDqXF1ZW1tZW50IMOpdHVkacOpcyBkYW5zIGxlIGNhZHJlIHNjb2xhaXJlLCDDoCBsYSBwb3N0w6lyaXTDqSBjdWx0dXJlbGxlbWVudCBpbXBvcnRhbnRlLCBwbHVzIHNvdXZlbnQgZCfDqXBvcXVlIGNsYXNzaXF1ZSwgb3UgY29tcGlsYW50IGRlIHByw6ljaWV1eCBmcmFnbWVudHMgZCfFk3V2cmVzIHBlcmR1ZXMuDQoNCkNyb2lzYW50IGNlcyBkZXV4IGRpbWVuc2lvbnMsIGxhIHF1ZXN0aW9uIGRlICoqbWFudXNjcml0cyoqIHBvdXJyYWl0IMOpZ2FsZW1lbnQgaW1wb3J0ZXIuIEVuIGVmZmV0LCB0b3VzIGxlcyBvdXZyYWdlcyBudW3DqXJpc8OpcyBkYW5zIGxlIFRMRyBvdSBQZXJzZXVzIG5haXNzZW50IGQndW5lIHRyYWRpdGlvbiwgZGlyZWN0ZSBvdSBpbmRpcmVjdGUuIFBvdXIgdW5lIG3Dqm1lIMWTdXZyZSwgaWwgcGV1dCBkb25jIHkgYXZvaXIgcGx1c2lldXJzIG1hbnVzY3JpdHMuIFBldXQtw6p0cmUgY2VzIG1hbnVzY3JpdHMgc2ltaWxhaXJlcyBtYWlzIGRpZmbDqXJlbnRzIG9udC1pbHMgZG9ubsOpIGxpZXUgw6AgZGVzIHNjaMOpbWFzIGQnYXR0cmlidXRpb25zIGQnaWRlbnRpZmlhbnRzIHNww6ljaWZpcXVlcywgb3UgcGV1dC3DqnRyZSBjZXJ0YWlucyBwYW5zIGRlIGxhIG51bcOpcm90YXRpb24gZMOpcGVuZGVudCBkZSBjZXR0ZSBsb2dpcXVlIHByb3ByZSBhdXggc291cmNlcywgcG91dmFudCBwYXIgZXhlbXBsZSByZWdyb3VwZXIgZGVzIHRleHRlcyBwcm92ZW5hbnQgZCd1biBtw6ptZSByZWN1ZWlsIGRlIGZyYWdtZW50cywgZCdhdXRhbnQgcGx1cyBwb3VyIGxlcyBjb3JwdXMgdnJhaXNlbWJsYWJsZW1lbnQgdHLDqHMgbGFjdW5haXJlcyBkw6lzaWduw6lzIHBhciBjZXJ0YWlucyBpZGVudGlmaWFudHMuIExhIHByaXNlIGVuIGNvbXB0ZSBkZSBsYSB0YWlsbGUgZGUgY2hhcXVlIGNvcnB1cyBwb3VycmFpdCBhbG9ycyDDoCBjZXQgw6lnYXJkIMOqdHJlIMOpY2xhaXJhbnRlLg0KDQojIyMjIE3DqXRob2RvbG9naWVzIGNvbXBsw6ltZW50YWlyZXMNCg0KIyMjIyMgUGlzdGVzIGV0aG5vZ3JhcGhpcXVlcw0KDQpDZXMgZGVybmnDqHJlcyByZW1hcnF1ZXMgbm91cyByZW52b2llbnQgw6AgbCdoaXN0b2lyZSBkZSBsYSBjb25zdGl0dXRpb24gZGVzIGNvcnB1cywgZXQgcGx1cyBzcMOpY2lmaXF1ZW1lbnQgZGVzIGJhc2VzIGRlIGRvbm7DqWVzIHF1ZSBzb250IGxlIFRMRyBldCAqUGVyc2V1cyouIENlcyBwbGF0ZWZvcm1lcyBvbnQgY29ubnUgZGlmZsOpcmVudGVzIHBoYXNlcyBkZSBkw6l2ZWxvcHBlbWVudCwgdnJhaXNlbWJsYWJsZW1lbnQgc291bWlzIGF1IGdyw6kgZGVzIGZpbmFuY2VtZW50cywgZGVzIGNhbXBhZ25lcyBkZSBudW3DqXJpc2F0aW9uLCBkZXMgcHJpb3JpdMOpcyBkdSBtb21lbnQsIGNlIHF1aSBpbmZsdWVuY2UgY2VydGFpbmVtZW50IGxhIG51bcOpcm90YXRpb24gZGVzIGF1dGV1cnMsIGV0IHBvdXJyYWl0IGVuIHBhcnRpY3VsaWVyIGV4cGxpcXVlciBsZXMgZGlmZsOpcmVudGVzIHPDqXF1ZW5jZXMgcXVlIG5vdXMgYXZvbnMgYXBlcsOndWVzIHBvdXIgbGUgVExHLiBUb3VzIGxlcyBhdXRldXJzLCB0b3V0ZXMgbGVzIMWTdXZyZXMgbidvbnQgcGFzIMOpdMOpIG51bcOpcmlzw6llcyBlbiB1bmUgc2V1bGUgZm9pcy4gTGUgVExHIGVuIGRvbm5lIGQnYWlsbGV1cnMgdW4gYXBlcsOndSBzdXIgbGEgcGFnZSBkJ2FjY3VlaWwgZGUgc29uIHNpdGUgaW50ZXJuZXQgZGUgbCfDqXZvbHV0aW9uIGRlcyBkb2N1bWVudHMgbnVtw6lyaXPDqXMuIExlcyBham91dHMgc3VjY2Vzc2lmcyBzb250IHRyw6hzIHLDqWd1bGllcnMsIGFwcGVsbGFudCDDoCBjaGFxdWUgZm9pcyBhdHRyaWJ1dGlvbiBkJ3VuZSBub3V2ZWwgaWRlbnRpZmlhbnQuDQoNCkRlcyBtYXTDqXJpYXV4IGV0aG5vZ3JhcGhpcXVlcywgY29tbWUgZGVzIGFyY2hpdmVzIGV0IGRlcyB0w6ltb2lnbmFnZXMsIHBsdXMgcHJvY2hlIGRlIG3DqXRob2RlcyBjbGFzc2lxdWVzIGQnaW52ZXN0aWdhdGlvbiBoaXN0b3JpcXVlLCBhcHBvcnRlcmFpZW50IMOgIGNldCBlbmRyb2l0IGRlcyDDqWNsYWlyYWdlcyB1dGlsZXMgcXVhbnQgw6AgbCdoaXN0b2lyZSBkZSBsYSBjb25zdGl0dXRpb24gZGUgY2VzIGNsYXNzaWZpY2F0aW9ucy4gw4AgY2V0IMOpZ2FyZCwgY2VydGFpbmVzIHNvdXJjZXMgYmlibGlvZ3JhcGhpcXVlcyBwb3VycmFpZW50IHZyYWlzZW1ibGFibGVtZW50IGNvbXBsw6l0ZXIgbCdhbmFseXNlLiBPbiBwb3VycmFpdCBub3RhbW1lbnQgc2UgcsOpZsOpcmVyIMOgIEJlcmtvd2l0eiBMdWNpLCAiQW5jaWxsYSB0byB0aGUgVGhlc2F1cnVzIExpbmd1YWUgR3JhZWNhZSA6IFRoZSBUTEcgQ2Fub24iICgqaW4qIEpvbiBTb2xvbW9uICjDqWQuKSwgKkFjY2Vzc2luZyBBbnRpcXVpdHkuIFRoZSBDb21wdXRlcml6YXRpb24gb2YgQ2xhc3NpY2FsIFN0dWRpZXMqIChwLiAzNC02MSksIFVuaXZlcnNpdHkgb2YgQXJpem9uYSBQcmVzcywgVHVjc29uLCAxOTkzKSwgY2hhcGl0cmUgZCdvdXZyYWdlIGRvbm5hbnQgZGVzIHByw6ljaXNpb25zIGludMOpcmVzc2FudGVzIHF1YW50IGF1IHLDtGxlIHF1J2Egam91w6kgbOKAmSpBbWVyaWNhbiBQaGlsb2xvZ2ljYWwgQXNzb2NpYXRpb24qLCB1biBkZSBzZXMgY29taXTDqXMgYXlhbnQgc8OpbGVjdGlvbm7DqSBsZXMgdGV4dGVzIMOgIGluY2x1cmUgZGFucyBsZSAqVGhlc2F1cnVzIExpbmd1YWUgR3JhZWNhZSouDQoNCiMjIyMjIFBpc3RlcyBpbmZvcm1hdGlxdWVzDQoNCkVuIHJlc3RhbnQgZGFucyBsJ2FuYWx5c2UgbnVtw6lyaXF1ZSwgaWwgZXhpc3RlIMOpZ2FsZW1lbnQgZGVzIHBpc3RlcyBldCBtw6l0aG9kZXMgcXVlIG5vdXMgbidhdm9ucyBwYXMgZXhwbG9yw6llcy4NCg0KTm90YW1tZW50LCBsZXMgaWRlbnRpZmlhbnRzIHBvdXJyYWllbnQgw6p0cmUgcGFyIGVuZHJvaXQgw6p0cmUgY29tcG9zw6lzIGRlIHBsdXNpZXVycyBmYWN0ZXVycywganVzdGFwb3jDqSBwb3VyIGRvbm5lciBsZSBub21icmUgcXVpIHNlcnQgZCdpZGVudGlmaWFudC4gUGFyIGV4ZW1wbGUsIGxlcyBkZXV4IHByZW1pZXJzIGNoaWZmcmVzIHBvdXJyYWllbnQgY29ycmVzcG9uZHJlIMOgIHVuZSB2YXJpYWJsZSwgZXQgbGVzIGRldXggc3VpdmFudHMgw6AgdW5lIGF1dHJlwqDigJMgY2VzIGRldXggY2hpZmZyZXMgc2VyYWllbnQgZW5zdWl0ZSBhZGpvaW50cyBwb3VyIGRvbm5lciB1biBpZGVudGlmaWFudCDDoCBxdWF0cmUgY2hpZmZyZXMuIENldHRlIGh5cG90aMOoc2UsIGVuY29yZSDDoCBleHBsb3JlciwgcG91cnJhaXQgY29udHJpYnVlciDDoCBleHBsaXF1ZXIgbGVzIHNhdXRzIGRlIG51bcOpcm90YXRpb24sIHZvaXJlIGxlcyBzw6lxdWVuY2VzIGp1c3F1ZSBsw6AgaW5jb21wcmlzZXMuDQoNCk5vdXMgbm91cyBzb21tZXMgZGUgcGx1cyBsaW1pdMOpcywgc3VyIGxlIHBsYW4gZGUgbCdhbmFseXNlIHN0YXRpc3RpcXVlLCBwcmluY2lwYWxlbWVudCDDoCBkZXMgZ3JhcGhpcXVlcyBlbiBkZXV4IG91IHRyb2lzIGRpbWVuc2lvbnMuIElsIGF1cmFpdCBwYXIgZXhlbXBsZSDDqXTDqSBwb3NzaWJsZSwgcG91ciBmYWlyZSBhcHBhcmHDrnRyZSBzdXIgdW5lIHNldWxlIGltYWdlIHVuZSBtdWx0aXBsaWNpdMOpIGRlIHZhcmlhYmxlcyBldCBuJ2VuIHJpZW4gcmF0ZXIsIGRlIHLDqWFsaXNhdGlvbiBwYXIgZXhlbXBsZSBkZXMgYW5hbHlzZXMgcGFyIGNvcnJlc3BvbmRhbmNlcyBtdWx0aXBsZXMgKEFDUCkuDQoNCiMjIEFubmV4ZXMNCg0KIyMjIEV4cGxvcmF0aW9ucyBzdWJzaWRpYWlyZXMNCg0KTm91cyBjb25zaWdub25zIGljaSBxdWVscXVlcyBhbmFseXNlcyBzdXBwbMOpbWVudGFpcmVzLCBub24gcGVhdWZpbsOpZXMgZXQgbm9uIGludMOpZ3LDqWVzIMOgIG5vdHJlIGTDqW1vbnN0cmF0aW9uLiBOb3VzIG5lIGxlcyBjb21tZW50ZXJvbnMgcGFzIG1haXMgbGVzIGxhaXNzb25zIMOgIGxhIGN1cmlvc2l0w6kgZHUgbGVjdGV1ci4NCg0KKlLDqWN1cMOpcmF0aW9uIGRlcyBob25vbnltZXMqDQpgYGB7cn0NCiMnIEdldCBob25vbnltcy4NCiMnIEBwYXJhbSBkZiBEYXRhZnJhbWUgb2YgYXV0aG9ycy4NCiMnIEByZXR1cm4gRGF0YWZyYW1lIG9mIGF1dGhvcnMgd2hvIGhhdmUgaG9ub255bXMuDQpnZXRfaG9tb255bXNfZGYgPC0gZnVuY3Rpb24oZGYpIHsNCiAgcmVzX2RmIDwtDQogICAgZGYgJT4lDQogICAgY291bnQobmFtZSwgbmFtZSA9ICJuYW1lX24iKSAlPiUNCiAgICBmaWx0ZXIobmFtZV9uID4gMSkgJT4lDQogICAgaW5uZXJfam9pbihkZiwgYnkgPSAibmFtZSIpICU+JQ0KICAgIHJlbG9jYXRlKG5hbWUsIG5hbWVfbiwgLmFmdGVyID0gaW5pdCkNCiAgcmV0dXJuKHJlc19kZikNCn0NCmdldF9ob21vbnltc19kZih0bGdfYXV0aG9yc19kZikNCiMgV2UgY2FuIG9ic2VydmUgMjE3IGhvbm9ueW1zIGluIGB0bGdfYXV0aG9yc19kZmAuDQojIEFlc2NoeWx1cyAoNXRoIEJDRSkgYXBwZWFycyBib3RoIHdpdGggY29kZSA4NSBhbmQgODg1Lg0KIyBYZW5vcGhvbiAoNHRoIEJDRSkgYXBwZWFycyBib3RoIHdpdGggY29kZSAzMiBhbmQgMTc1NC4NCmdldF9ob21vbnltc19kZihwaGlfYXV0aG9yc19kZikNCiMgV2UgY2FuIG9ic2VydmUgMTIgaG9ub21ueW1zIGluIGBwaGlfYXV0aG9yc19kZmAgKHRob3NlIGxhc3QgYXJlIG9ubHkgbi9hKS4NCmBgYA0KDQoqRXhwbG9yYXRpb25zIHN1YnNpZGlhaXJlcyBkZXMgZG9ubsOpZXMqDQpgYGB7cn0NCnRsZ19hdXRob3JzX2RmICU+JSBmaWx0ZXIoc3RyX2RldGVjdChuYW1lLCAiKD9pKWVwaXN0dWwiKSkNCnRsZ19hdXRob3JzX2RmICU+JSBmaWx0ZXIoc3RyX2RldGVjdChuYW1lLCAiKD9pKWFub255bSIpKQ0KdGxnX2F1dGhvcnNfZGYgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KG5hbWUsICIoP2kpcGFyYWRveCIpKQ0KYGBgDQoNCipBbmFseXNlIGRlIGNvcnJlc3BvbmRhbmNlcyBwcmluY2lwYWxlcyoNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoRmFjdG9NaW5lUiwgZHVtbXkpDQoNCiMgVE9ETzogQ29kZSBgaW5pdGAgaW50byBvbmUgbnVtZXJpYyB2YXJpYWJsZSwgZnJvbSAxIHRvIDI2Lg0KDQojJyBGb3JtYXQgYW4gYXV0aG9ycyBkYXRhZnJhbWUNCiMnIHNvIGl0IGNhbiBiZSBzZW5kIHRvIHRoZSBgUENBKClgIGZ1bmN0aW9uLg0KIycgQHBhcmFtIGRmIERhdGFmcmFtZSB0byBmb3JtYXQuDQojJyBAcGFyYW0gZ2VucmUgQm9vbGVhbiBpbmRpY2F0aW5nIGlmICJnZW5yZSIgaXMgcHJlc2VudCBpbiB0aGUgZGYuDQpmb3JtYXRfdG9fcGNhX2RmIDwtIGZ1bmN0aW9uKGRmLCBnZW5yZSA9IFRSVUUpIHsNCiAgcmVzX2RmIDwtDQogICAgZGYgJT4lDQogICAgIyBEcm9wIHVzZWxlc3MgdmFyaWFibGVzIGFuZCBOQQ0KICAgIHNlbGVjdCgtbmFtZSwgLWRhdGVfYWN0aXZlLCAtZGF0ZV9hY3RpdmVfc3RyLCAtZGF0ZV9iZWdpbl9zdHIsIC1kYXRlX2VuZF9zdHIpICU+JQ0KICAgIGRyb3BfbmEoKSAlPiUNCiAgICAjIERpY2hvdG9taXplIHF1YWxpdGF0aXZlIHZhcmlhYmxlcywNCiAgICAjIHRvIHRyYW5zZm9ybSB0aGVtIGludG8gcXVhbnRpdGF0aXZlIG9uZXMuDQogICAgIyBJdCBpcyBpbnNwaXJlZCBieSB0aGUgbWV0aG9kIHVzZWQgaW4gbG9naXN0aWMgcmVncmVzc2lvbi4NCiAgICBtdXRhdGUoZHVtbXkodGliYmxlKHBsYWNlKSkpICU+JQ0KICAgIG11dGF0ZShkdW1teSh0aWJibGUoaW5pdCkpKSAlPiUNCiAgICBzZWxlY3QoLWluaXQsIC1wbGFjZSkNCiAgaWYgKGdlbnJlKSB7DQogICAgcmVzX2RmIDwtIHJlc19kZiAlPiUgDQogICAgICBtdXRhdGUoZHVtbXkodGliYmxlKGdlbnJlKSkpICU+JQ0KICAgICAgc2VsZWN0KC1nZW5yZSkNCiAgfQ0KICByZXNfZGYgPC0gcmVzX2RmICU+JQ0KICAgIG11dGF0ZV9hbGwoYXMubnVtZXJpYykNCiAgcmV0dXJuKHJlc19kZikNCn0NCg0KcGhpX3BjYV9kZiA8LSBmb3JtYXRfdG9fcGNhX2RmKHBoaV9hdXRob3JzX2RmLCBnZW5yZSA9IEZBTFNFKQ0KcGhpX3BjYSA8LSBQQ0EocGhpX3BjYV9kZikNCg0KdGxnX3BjYV9kZiA8LSBmb3JtYXRfdG9fcGNhX2RmKHRsZ19hdXRob3JzX2RmKQ0KdGxnX3BjYSA8LSBQQ0EodGxnX3BjYV9kZikNCg0KIyBBIGNvcnJlbGF0aW9uIGJldHdlZW4gYGNvZGVgIGFuZCBgZGF0ZWAgc2VlbXMgdG8gYXBwZWFyLg0KIyBUaG9zZSBhcmUgdGhlIHZhcmlhYmxlcyB0aGF0IGRpZmZlcmVuY2lhdGUgdGhlIG1vc3QgaW5kaXZpZHVhbHMuDQojIEluaXRpYWxzIHNlZW0gdG8gaGF2ZSBubyBjb3JyZWxhdGlvbiB3aXRoIHRob3NlIHR3bywNCiMgYW5kIHRvIGNoYXJhY3Rlcml6ZSB0aGUgbW9zdCB0aGUgc2Vjb25kIGRpbWVuc2lvbi4NCmBgYA0KDQojIyMgQ29kZSBkZSBkw6ltb25zdHJhdGlvbg0KDQoqU8OpbGVjdGlvbiBkYW5zIHVuIHRhYmxlYXUqDQpgYGB7ciwgZGVtby1zZWxlY3QsIGV2YWwgPSBGQUxTRX0NCnRtcCA8LQ0KICB0bGdfYXV0aG9yc19kZiAlPiUNCiAgIyBTZWxlY3QgY29sdW1ucw0KICBzZWxlY3QobmFtZSwgY29kZSwgZGF0ZV9hY3RpdmUpICU+JQ0KICAjIERyb3AgbWlzc2luZyB2YWx1ZXMNCiAgZHJvcF9uYShkYXRlX2FjdGl2ZSkNCmBgYA0KDQoqTm90aWNlIGRlIHNww6ljaWZpY2F0aW9ucyB0ZWNobmlxdWVzLCBwb3VyIGV4cGxpY2l0ZXIgbCdlbnZpcm9ubmVtZW50IGRlIGTDqXZlbG9wcGVtZW50IHV0aWxpc8OpKg0KYGBge3J9DQojJyBBIGxpc3Qgb2YgbG9hZGVkIHBhY2thZ2VzLCB3aXRoIHRoZWlyIHJlc3BlY3RpdmUgdmVyc2lvbnMuDQojJyBAcmV0dXJuIHN0cg0KcGFja2FnZXNfc3RyIDwtIGZ1bmN0aW9uKCkgew0KICBwYWNrYWdlcyA8LSBwYWNtYW46OnBfbG9hZGVkKCkgJT4lIHNvcnQoKQ0KICBwYWNrYWdlX3N0cl92IDwtIHBhY2thZ2VzICU+JQ0KICAgIG1hcCh+IHBhc3RlMCgiLSAiLC4sIiB2IixwYWNtYW46OnBfdmVyc2lvbiguKSkpDQogIHN0ciA8LSBwYXN0ZShwYWNrYWdlX3N0cl92LCBjb2xsYXBzZSA9ICJcbiIpDQogIHJldHVybihzdHIpDQp9DQoNCiMnIEEgdGVjaG5pY2FsIG5vdGljZQ0KIycgQGRldGFpbHMgRGlzcGxheToNCiMnICAgLSBleGFjdCBkYXRlIG9mIGRvY3VtZW50IGdlbmVyYXRpb24NCiMnICAgLSBPUyB1c2VkDQojJyAgIC0gUiB2ZXJzaW9uIHVzZWQNCiMnICAgLSBQYWNrYWdlcyBsb2FkZWQgd2l0aCB0aGVpciB2ZXJzaW9uICANCiMnIFVzZSBpbiB0aGUgdGV4dCBib2R5IG9mIHRoZSBgLnJtZGAgZG9jdW1lbnQNCiMnIHdpdGggYHIgdGVjaG5pY2FsX25vdGljZV9zdHIoKWAuDQojJyBAcmV0dXJuIHN0cg0KdGVjaG5pY2FsX25vdGljZV9zdHIgPC0gZnVuY3Rpb24oKSB7DQogIHJldHVybihwYXN0ZTAoDQoiTGUgcHLDqXNlbnQgZG9jdW1lbnQgYSDDqXTDqSBnw6luw6lyw6kgbGUgIixmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICViICVZIMOgICVYIiksIiBzb3VzICIsc3RyX3RvX3RpdGxlKC5QbGF0Zm9ybSRPUy50eXBlKSwiIGF2ZWMgbGVzIHJlc3NvdXJjZXMgc3VpdmFudGVzwqA6DQoNCi0gIixSLnZlcnNpb24uc3RyaW5nLCINCg0KKkJpYmxpb3Row6hxdWVzIGV4dGVybmVzKg0KDQoiLHBhY2thZ2VzX3N0cigpDQogICkpDQp9DQpgYGANCg0KIyMjIE1vZHVsZSBkJ2V4cG9ydGF0aW9uDQoNCmBgYHtyIGV4cG9ydH0NCndyaXRlX2NzdihwaGlfYXV0aG9yc19kZiwgaGVyZSgicHJvamV0X2ZpbmFsL291dHB1dC9waGlfYXV0aG9yc19kZi5jc3YiKSkNCndyaXRlX2Nzdih0bGdfYXV0aG9yc19kZiwgaGVyZSgicHJvamV0X2ZpbmFsL291dHB1dC90bGdfYXV0aG9yc19kZi5jc3YiKSkNCmBgYA0KDQojIyMgUsOpZsOpcmVuY2VzDQoNCiMjIyMgUmVzc291cmNlcyBleHRlcm5lcw0KDQotICoqUGVyc2V1cyBQcm9qZWN0KiosICJBdXRob3JzLUFiYnJldmlhdGlvbi1FZGl0aW9ucyIsIFRhYmxldXIgZW4gbGlnbmUgKFtsaWVuXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xUkhONktCdWxER2JwS0FUTFU2UHR3VTRvNXhWc2FCQjZ4YlFSdEtqTXlXRS9lZGl0KSkuDQoNCi0gKipDbGFzc2ljYWwgTGFuZ2FnZSBUb29sS2l0KiosICJBdXRob3ItRXBpdGhldCIsIEZpY2hpZXIgLmpzb24gKFtsaWVuXShodHRwczovL2dpdGh1Yi5jb20vY2x0ay9jbHRrL2Jsb2IvbWFzdGVyL2NsdGsvY29ycHVzL2dyZWVrL3RsZy9hdXRob3JfZXBpdGhldC5qc29uKSkuDQoNCi0gKipJbnRlcm5ldCoqIGV0IHNlcyBpbm5vbWJyYWJsZXMgcmVzc291cmNlcyBwb3VyIGFwcHJlbmRyZSBldCByw6lwb25kcmUgYXV4IHByb2Jsw6htZXMgdGVjaG5pcXVlcyByZW5jb250csOpcy4NCg0KIyMjIyBFbnZpcm9ubmVtZW50IGRlIGTDqXZlbG9wcGVtZW50DQoNCmByIHRlY2huaWNhbF9ub3RpY2Vfc3RyKClgDQoNCiMjIyBIaXN0b3JpcXVlIGRlcyB2ZXJzaW9ucw0KDQojIyMjIHYxLjQtdHJpc3Rhbi4xDQoNCi0gQ29ycmVjdGlvbnMgZXQgYWp1c3RlbWVudHMgZGl2ZXJzDQogIC0gQ29ycmVjdGlvbnMgZGFucyBsZXMgZm9ybXVsYXRpb25zDQogIC0gUsOpw6ljcml0dXJlcyBwYXJ0aWVsbGVzIG5vdGFtbWVudCBkYW5zIGwnaW50cm9kdWN0aW9uIGV0IGxhIGNvbmNsdXNpb24NCiAgLSBDb25zaWTDqXJhdGlvbnMgZGUgbWlzZSBlbiBwYWdlDQogIC0gRXhwbGljaWF0aW9uIGR1IGNvZGUgZGUgbGEgbm90aWNlIHRlY2huaXF1ZQ0KICAtIFJlbXBsYWNlbWVudCBkZSBgY29sb3VyYCBwYXIgYGNvbG9yYCBwb3VyIGhvbW9nw6luw6lpc2VyIGwnb3J0aG9ncmFwaGUsIGVuIGZhdmV1ciBkZSBsYSBwbHVzIGNvdXJ0ZQ0KLSBBam91dHMgZGl2ZXJzDQogIC0gRXhwbGljaXRhdGlvbiBzdXBwbMOpbWVudGFpcmUgcXVhbnQgYXUgcHJpbmNpcGUgZCd1biB0YWJsZWF1IGRlIGRvbm7DqWVzDQogIC0gQ3LDqWF0aW9uIGQndW5lIHNlY3Rpb24gIkFuYWx5c2Ugc3Vic2lkaWFpcmUiIGV0IGludMOpZ3JhdGlvbiBkJ3VuZSB0ZW50YXRpdmUgZCdBQ1ANCiAgLSBBam91dCBkZSB0ZXN0cyBkZSBjb3Jyw6lsYXRpb24gKGlkZW50aWZpYW50IGV0IGRhdGUsIGBjb3IudGVzdCgpYCkNCiAgLSBBam91dCBkJ3VuZSBmb25jdGlvbiBwb3VyIGFqdXN0ZXIgbCdhZmZpY2hhZ2UgZGVzIHZlY3RldXJzIChgcHJpbnRfdmVjdG9yKClgKQ0KDQojIyMjIHYxLjMgKDIwMjEtMDItMDlUMTg6MzApDQoNCi0gRnVzaW9uIGRlcyB2ZXJzaW9ucyB2MS4zLWZsb3JlbmNlLCB2MS4zLW5hZGluZS4yIGV0IHYxLjMtdHJpc3Rhbi4NCg0KIyMjIyB2MS4zLXRyaXN0YW4gKDIwMjEtMDItMDlUMTg6MjApDQoNCi0gQWpvdXQgZGUgZm9uY3Rpb25zIGQnZXhwbG9yYXRpb24gKHNlY3Rpb24gIkNvZGUgZGUgZMOpbW9uc3RyYXRpb24iKQ0KDQojIyMjIHYxLjMtbmFkaW5lLjIgKDIwMjEtMDItMDlUMTI6NTEpDQoNCi0gQ29ycmVjdGlvbiBkZSBsaWVucyBpbnRlcm5lcw0KDQojIyMjIHYxLjMtbmFkaW5lLjEgKDIwMjEtMDItMDdUMTQ6NDApDQoNCi0gUHLDqWNpc2lvbnMgc3VyIGxlcyBsaWV1eCBldCBsZXMgbm9tcyBkJ2F1dGV1cnMgZGFucyAiMS4gRm9ybWF0YWdlIGRlcyBkb25uw6llcyA+IFZhcmlhYmxlcyByZWNoZXJjaMOpZXMiDQotIENvcnJlY3Rpb24gZGUgZGV1eCBncmFwaGlxdWVzIG91Ymxpw6lzIChvcmRyZSBhbHBoYWLDqXRpcXVlKQ0KLSBBam91dCBkJ3VuIHBldGl0IHBhcmFncmFwaGUgc3VyIGxlcyBsaWV1eCBkYW5zICJDb25jbHVzaW9ucyA+IExlcyBsaW1pdGVzIGRlIG5vdHJlIG3DqXRob2RlIg0KDQojIyMjIHYxLjMtZmxvcmVuY2UgKDIwMjEtMDItMDhUMTI6MzMpDQoNCi0gQWpvdXRzIGRlIHByw6ljaXNpb24gw6AgbGEgc3VpdGUgZGVzIGNvbW1lbnRhaXJlcyBkJ0F1csOpbGllbiBCZXJyYQ0KLSBSZWxlY3R1cmUgb3J0aG9ncmFwaGlxdWUgZXQgZ3JhbW1hdGljYWxlDQoNCiMjIyMgdjEuMiAoMjAyMS0wMi0wNlQxNzo0MCkNCg0KLSBGdXNpb24gZGVzIHZlcnNpb25zIHYxLjItbmFkaW5lLjQgZXQgdjEuMi10cmlzdGFuLCBxdWkgY29uc2lzdGVudCBlbiB1biBkw6lidXQgZGUgcHJpc2UgZW4gY29tcHRlIGRlcyBjb21tZW50YWlyZXMgZCdBdXLDqWxpZW4gQmVycmENCg0KIyMjIyB2MS4yLXRyaXN0YW4gKDIwMjEtMDItMDZUMTU6MjApDQoNCi0gQW5hbHlzZXMgY29tcGzDqW1lbnRhaXJlcw0KICAtIEFqb3V0IGRlIGRldXggZ3JhcGhpcXVlcyBxdWFudCBhdXggcHJlbWnDqHJlcyBhbmFseXNlcyBzdXIgbGVzIGdlbnJlcw0KICAtIEFqb3V0IGQnYW5hbHlzZXMgcGFyIG1vZMOobGVzIGxpbsOpYWlyZXMgcG91ciBwcsOpY2lzZXIgbGEgY29ycsOpbGF0aW9uIGVudHJlIGlkZW50aWZpYW50cyBldCBkYXRlcyBjaGV6IGxlcyBsYXRpbnMNCi0gQ2hhbmdlbWVudHMgbWluZXVycw0KICAtIENsYXJpZmljYXRpb24gZGUgbGEgbWVzdXJlIGRlcyB2YWxldXJzIG1hbnF1YW50ZXMgKGBuYV9wYCByZW5vbW3DqWUgYG5hX3JhdGVgIGV0IGFycm9uZGllKQ0KICAtIFByw6ljaXNpb24gc3VyIGxhIGxpc3RlIGRlcyDDqXF1aXZhbGVudHMgw6AgZGVzIHZhbGV1cnMgbWFucXVhbnRlcw0KICAtIFByw6ljaXNpb24gc3VyIGxlcyBiYWxpc2VzIEJDRS9DRSBjb21tZSBmYWN0ZXVyIGNvbW11bg0KICAtIENvcnJlY3Rpb24gbWFudWVsbGUgcG91ciBUTEcjMDIzNyAoQW5hY3LDqW9uKQ0KICAtIENvcnJlY3Rpb25zIG1pbmV1cmVzDQoNCiMjIyMgdjEuMi1uYWRpbmUuNCAoMjAyMS0wMi0wNlQxNzoxMykNCg0KLSBDb3JyZWN0aW9ucyBldCBzdXBwcmVzc2lvbiBkZSBjZXJ0YWlucyBjb21tZW50YWlyZXMgc3VyIGxlcyBnZW5yZXMNCg0KIyMjIyB2MS4yLW5hZGluZS4zICgyMDIxLTAyLTA2VDAxOjM5KQ0KDQotIENvbW1lbnRhaXJlcyBldCBjb3JyZWN0aW9ucw0KDQojIyMjIHYxLjItbmFkaW5lLjIgKDIwMjEtMDItMDVUMTc6MDApDQoNCi0gUsOpaW50w6lncmF0aW9uIGRlcyBtb2RpZmljYXRpb25zIGRlIGxhIHYxLjEgKGxhIHYxLjAgYXZhaXQgw6l0w6kgcHJpc2UgY29tbWUgb3JpZ2luZSBkZSBsYSB2MS4yLW5hZGluZS4xKQ0KDQojIyMjIHYxLjItbmFkaW5lLjEgKDIwMjEtMDItMDRUMjI6NDMpDQoNCi0gTWlzZSBlbiBvcmRyZSBhbHBoYWLDqXRpcXVlIGRhbnMgbGUgc2VucyBkZSBsYSBsZWN0dXJlIChiYXMgZW4gaGF1dCkgc3VyIGxlcyBncmFwaGlxdWVzLCBldCBjb3JyZWN0aW9ucyBkZXMgaW50ZXJwcsOpdGF0aW9ucyBlbiBjZSBzZW5zDQoNCiMjIyMgdjEuMSAoMjAyMS0wMS0xMVQxMzowMCkNCg0KLSBQcsOpY2lzaW9ucyBldCBjb3JyZWN0aW9ucyBkYW5zIGwnaW50cm9kdWN0aW9uIGV0IGxhIGNvbmNsdXNpb24NCi0gUmVuZHUgZW4gY2FybmV0ICgqbm90ZWJvb2sqKSwgYXZlYyB0YWJsZSBkZXMgbWF0acOocmVzIGZsb3R0YW50ZQ0KDQojIyMjIHYxLjAgKDIwMjEtMDEtMTFUMDE6MjkpDQoNCi0gSW50w6lncmF0aW9uIGRlIGwnaW50cm9kdWN0aW9uIGV0IGRlIGxhIGNvbmNsdXNpb24NCi0gRGVybmnDqHJlcyB2w6lyaWZpY2F0aW9ucyBkZXMgY29tbWVudGFpcmVzDQotIFbDqXJpZmljYXRpb25zIHR5cG9ncmFwaGlxdWVzDQoNCiMjIyMgdjAuMTQgKDIwMjEtMDEtMTBUMjI6NTApDQoNCi0gQWpvdXQgZCd1biBlbXBsYWNlbWVudCBwb3VyIGxhIHNlY3Rpb24gImNvbmNsdXNpb24iDQotIFN1cHByZXNzaW9uIGRlcyDDqWzDqW1lbnRzIGludXRpbGVzDQotIFByw6ljaXNpb25zIMOgIGxhIGZpbiBkZSBsYSBzZWN0aW9uICJkw6ltYXJjaGUiDQotIFByw6ljaXNpb25zIMOgIGxhIGZpbiBkZSBsYSBzZWN0aW9uICJpZGVudGlmaWFudHMsIGRhdGVzIGV0IGluaXRpYWxlcyIgcG91ciBsZXMgbGF0aW5zDQotIFByw6ljaXNpb25zIGV0IGFqb3V0cyBhdSBkw6lidXQgZXQgw6AgbGEgZmluIGRlIGxhIHNlY3Rpb24gImdlbnJlcyINCi0gUHLDqWNpc2lvbnMgYXUgZMOpYnV0IGRlIGxhIHNlY3Rpb24gImxpZXV4Ig0KLSBBbcOpbGlvcmF0aW9ucyBtaW5ldXJlcw0KDQojIyMjIHYwLjEzICgyMDIxLTAxLTEwVDE0OjAwKQ0KDQotIENvcnJlY3Rpb25zIG9ydGhvZ3JhcGhpcXVlcw0KLSBBam91dCBkJ3VuZSBhbmFseXNlIHBhciBsaWV1eA0KDQojIyMjIHYwLjEyICgyMDIxLTAxLTA5VDIyOjUwKQ0KDQotIFLDqWRhY3Rpb24gZGUgbGEgc2VjdGlvbiAiW0TDqW1hcmNoZSBhZG9wdMOpZV0oI2TDqW1hcmNoZS1hZG9wdMOpZSkiDQoNCiMjIyMgdjAuMTEgKDIwMjEtMDEtMDlUMTk6NDUpDQoNCi0gQW3DqWxpb3JhdGlvbnMgKHBsZWluc8KgISkNCg0KIyMjIyB2MC4xMCAoMjAyMS0wMS0wOVQxMzo0MCkNCg0KLSBSw6lpbnTDqWdyYXRpb24gZGVzIHZlcnNpb25zIGludGVybcOpZGlhaXJlcyBkZSBOYWRpbmUgZXQgRmxvcmVuY2UNCg0KTm9tIG9yaWdpbmFsIHwgVmVyc2lvbiBjb3JyZXNwb25kYW50ZQ0KLS0tIHwgLS0tDQp2MC41IChtb2RpZmnDqWUpIC8gdjAuNiB8IHYwLjYNCnYwLjVuYWQgfCB2MC43DQp2MC41TmFkLTdqYW52IHwgdjAuOA0KdjAuNU5hZC04amFudiB8IHYwLjkNCg0KLSBBbmFseXNlcyBncmFwaGlxdWVzDQogIC0gRW4gZGV1eCBkaW1lbnNpb25zwqA6IGNvZGUgZXQgbm9tLCBjb2RlIGV0IGRhdGUNCiAgLSBFbiB0cm9pcyBkaW1lbnNpb25zwqA6IGNvZGUsIGRhdGUsIGdlbnJlDQotIE5vdXZlYXUgdGFibGVhdSBwb3VyIGxlcyBsYXRpbnMgZW4gcmV0aXJhbnQgbGVzIHByw6lub21zDQotIEFtw6lsaW9yYXRpb24gZGUgbGEgc3RydWN0dXJlDQotIEFtw6lsaW9yYXRpb25zIG1pbmV1cmVzIHBhciBlbmRyb2l0cw0KLSBSw6lkYWN0aW9uIHBhcnRpZWxsZSBkJ2V4cGxpY2F0aW9ucyBwbHVzIGfDqW7DqXJhbGVzDQotIExlcyBiYWxpc2VzICJAISIgaW5kaXF1ZW50IHF1ZSBsJ8OpbMOpbWVudCBhc3NvY2nDqSBkZW1hbmRlIHbDqXJpZmljYXRpb24gdm9pcmUgc3VwcHJlc3Npb24NCg0KIyMjIyB2MC41ICgyMDIxLTAxLTA1VDIwOjIwKQ0KDQotIENvcnJlY3Rpb24gZCd1bmUgZXJyZXVywqA6IGxlcyBsaWduZXMgbifDqXRhaWVudCBwYXMgZMOpZ3JvdXDDqWVzIGFwcsOocyBmb3JtYXRhZ2UgZGVzIGRhdGVzDQotIEFkam9uY3Rpb24gZGVzIGdlbnJlcw0KLSBEw6lwbGFjZW1lbnQgZGUgbGEgY29sb25uZSBkZXMgY29kZXMgYXUgZMOpYnV0IHBvdXIgY2xhcnTDqQ0KLSBQb3NzaWJsZXMgYXV0cmVzIGNoYW5nZW1lbnRzIG1pbmV1cnMNCg0KIyMjIyB2MC40ICgyMDIxLTAxLTA1VDE2OjQwKQ0KDQotIEZvcm1hdGFnZSBkZXMgbGlldXgNCi0gUHLDqXNlbnRhdGlvbiBjb252ZW5hYmxlIGRlcyB2YXJpYWJsZXMgY29uc2VydsOpZXMgZGVwdWlzIGxlIHRhYmxldXIgKlBlcnNldXMqDQotIENvcnJlY3Rpb25zIG1pbmV1cmVzIGRpdmVyc2VzDQoNCiMjIyMgdjAuMyAoMjAyMS0wMS0wNVQxMjoxMCkNCg0KLSBDb3JyZWN0aW9uIGQndW5lIGVycmV1ciBkYW5zIGxhIHLDqWN1cMOpcmF0aW9uIGRlcyBjb2Rlcw0KKHBvdXIgYmllbiByw6ljdXDDqXJlciBsZXMgYXV0ZXVycyBkb250IGxlIGNvZGUgZXN0IGluZsOpcmlldXIgw6AgMTAwMCkNCi0gVXRpbGlzYXRpb24gZGUgbGEgbW95ZW5uZSBwbHV0w7R0IHF1ZSBkZSBsYSB2YWxldXIgZGUgZ2F1Y2hlLA0KcXVhbmQgbGEgZGF0ZSBkb25uw6llIGVzdCB1biBpbnRlcnZhbGxlIChwb3VyIGxhIHRyYW5zZm9ybWVyIGVuIG5vbWJyZSkNCi0gQ2hhbmdlbWVudHMgYW5lY2RvdGlxdWVzDQogIC0gQWpvdXQgZW4gYW5uZXhlcyBkZSBjb2RlcyBkZSBkw6ltb25zdHJhdGlvbg0KICAtIEFqb3V0IGVuIGFubmV4ZXMgZCd1biBtb2R1bGUgZCdleHBvcnRhdGlvbg0KICAtIEFqb3V0IGVuIGFubmV4ZXMgZGUgbGEgbGlzdGUgZGVzIGTDqXBlbmRhbmNlcywgZ8OpbsOpcsOpZSBkeW5hbWlxdWVtZW50DQogIC0gQWpvdXQgZCd1bmUgc2VjdGlvbiBzdXIgbGVzIHBvc3NpYmxlcyBlcnJldXJzIGRhbnMgbGVzIGRhdGVzIGRlcyBkb25uw6llcyByw6ljdXDDqXLDqWVzDQotIENoYW5nZW1lbnRzIG1pbmV1cnMNCiAgLSDDgCBsJ2ludMOpcmlldXIgZGUgYGNvbnZlcnRfZGF0ZXMoKWAsIHJlbm9tbWFnZSBkZSBgaXNfYmVmb3JlYCBlbiBgaXNfYmNlYA0KICAtIFN1cHByZXNzaW9uIGRlcyB2YWxldXJzIG1hbnF1YW50ZXMgcG91ciBsYSBjb2xvbm5lIGBjb2RlYC4NCiAgLSBDb3JyZWN0aW9ucyBkJ2VycmV1cnMgb3J0aG9ncmFwaGlxdWVzIGRhbnMgbGEgZG9jdW1lbnRhdGlvbg0KDQojIyMjIHYwLjIgKDIwMjAtMTItMzFUMTU6NDApDQoNCi0gQ29tcGzDqXRpb24gZHUgZm9ybWF0YWdlIGRlcyBkYXRlcw0KLSBBam91dCBkZSByZW1hcnF1ZXMgc3VyIGxlcyBkYXRlcyBldCBsYSBiaWJsaW90aMOocXVlIGBsdWJyaWRhdGVgDQotIENvcnJlY3Rpb24gZCdlcnJldXJzIHBvbmN0dWVsbGVzIGRhbnMgbGVzIGRvbm7DqWVzDQoNCiMjIyMgdjAuMSAoMjAyMC0xMi0zMVQxMjo1MCkNCg0KLSBTdHJ1Y3R1cmUgZ8OpbsOpcmFsZSBkdSBkb2N1bWVudA0KLSBDb25maWd1cmF0aW9uIGR1IGZpY2hpZXIgUk1hcmtkb3duDQotIEV4dHJhY3Rpb24gZGUgbGEgbGlzdGUgZGVzIGF1dGV1cnMgZGVwdWlzIGxlIHRhYmxldXIgZHUgKlByb2pldCBQZXJzZXVzKg0KLSBEw6lidXQgZGUgZm9ybWF0YWdlIGRlcyBkYXRlcw0K